Raised when the assertDeterministicCompute invariant gate detects a derivation whose compute(get) returns a different value on the second call against the same dependency snapshot — i.e. the compute is not a pure function of its declared dependencies (SPEC §15.1).

SPEC §15.1 requires that every derived value satisfy derived(t) = f(b₁(t), …, bₙ(t)) — a pure function of its dependencies sampled at the same commit moment. The denotational definition forbids hidden inputs: a compute that reads Math.random(), Date.now(), an external mutable cell, or any value not surfaced through the tracked get accessor breaks the equation, because two calls against the same get return values disagree.

The audit's adversarial-fanin scenario (#718) injects Math.random() returns into 0.1% of derivations and asks the engine to detect them. The detection strategy this error tags is second-call equality: after the first compute records its dependencies and a value, the engine re-invokes the compute against an accessor that returns the same upstream values, and compares the second result with the first via Object.is. A mismatch is the structural witness of non-determinism.

Opt-in via experimentalFlags: { assertDeterministicCompute: true } (env var CAUSL_ASSERT_DETERMINISTIC_COMPUTE=1). The flag defaults to false because the gate doubles compute() work; production pays zero cost. The flag is intended for dev / test / CI where the cost is acceptable as the price of a structural invariant gate.

The path field carries every node id traversed at detection time, ending with the offending node. Mirrors CycleError's path shape so callers branching on instanceof CauslError get a consistent debug surface.

The derived node whose compute returned a different value on the second call.

Ordered ids from the recompute root down to id, so callers can locate the offending node in a deeper graph.

Hierarchy (View Summary)

Constructors

Properties

cause?: unknown
id: string
kind: "NonDeterministicCompute" = ...

Discriminated tag for exhaustive matching.

message: string
name: string = 'NonDeterministicComputeError'
path: readonly string[]
stack?: string
stackTraceLimit: number

The Error.stackTraceLimit property specifies the number of stack frames collected by a stack trace (whether generated by new Error().stack or Error.captureStackTrace(obj)).

The default value is 10 but may be set to any valid JavaScript number. Changes will affect any stack trace captured after the value has been changed.

If set to a non-number value, or set to a negative number, stack traces will not capture any frames.

Methods

  • Creates a .stack property on targetObject, which when accessed returns a string representing the location in the code at which Error.captureStackTrace() was called.

    const myObject = {};
    Error.captureStackTrace(myObject);
    myObject.stack; // Similar to `new Error().stack`

    The first line of the trace will be prefixed with ${myObject.name}: ${myObject.message}.

    The optional constructorOpt argument accepts a function. If given, all frames above constructorOpt, including constructorOpt, will be omitted from the generated stack trace.

    The constructorOpt argument is useful for hiding implementation details of error generation from the user. For instance:

    function a() {
    b();
    }

    function b() {
    c();
    }

    function c() {
    // Create an error without stack trace to avoid calculating the stack trace twice.
    const { stackTraceLimit } = Error;
    Error.stackTraceLimit = 0;
    const error = new Error();
    Error.stackTraceLimit = stackTraceLimit;

    // Capture the stack trace above function b
    Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
    throw error;
    }

    a();

    Parameters

    • targetObject: object
    • OptionalconstructorOpt: Function

    Returns void