different-ai/openwork · error · InterpreterRuntimeError

Cannot access '${name}' before initialization.

Error message

Cannot access '${name}' before initialization.

What it means

Reading an identifier whose binding exists but is not yet initialized reproduces JavaScript's temporal dead zone (TDZ) as a ReferenceError. This occurs specifically for parameter default expressions that forward-reference a later parameter of the same function — the binding is registered but flagged initialized === false until its default is evaluated.

Source

Thrown at packages/codemode/src/interpreter/runtime.ts:3281

    // anything else already present is a genuine duplicate declaration.
    const existing = scope.get(name)
    if (existing && existing.initialized !== false) {
      throw new InterpreterRuntimeError(`Identifier '${name}' has already been declared.`, node)
    }

    scope.set(name, { mutable, value, initialized: true })
  }

  private getIdentifierValue(name: string, node: AstNode): unknown {
    const binding = this.resolveBinding(name)

    if (!binding) {
      throw new InterpreterRuntimeError(`Unknown identifier '${name}'.`, node).as("ReferenceError")
    }

    // A parameter default that forward-references a later (not-yet-bound) parameter - JS TDZ.
    if (binding.initialized === false) {
      throw new InterpreterRuntimeError(`Cannot access '${name}' before initialization.`, node).as("ReferenceError")
    }

    return binding.value
  }

  private setIdentifierValue(name: string, value: unknown, node: AstNode): unknown {
    const binding = this.resolveBinding(name)

    if (!binding) {
      throw new InterpreterRuntimeError(`Unknown identifier '${name}'.`, node).as("ReferenceError")
    }

    if (!binding.mutable) {
      throw new InterpreterRuntimeError(`Cannot assign to constant '${name}'.`, node).as("TypeError")
    }

    binding.value = value
    return value

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Reorder parameters so defaults only reference earlier parameters: `function f(b = 2, a = b)`.
  2. Inline the default expression instead of referencing the later parameter.
  3. Compute the value inside the function body: `function f(a, b = 2) { a = a ?? b; }`.

Example fix

// before
function f(a = b, b = 2) { ... }
// after
function f(b = 2, a = b) { ... }
Defensive patterns

Strategy: try-catch

Validate before calling

// statically reject parameter defaults referencing later params
for (let i = 0; i < params.length; i++) {
  for (let j = i + 1; j < params.length; j++) {
    if (defaultRefs(params[i], params[j].name)) throw new Error(`default of '${params[i].name}' references later param '${params[j].name}'`);
  }
}

Try / catch

try {
  const result = await interpret(src);
} catch (e) {
  if (e instanceof InterpreterRuntimeError && e.message.endsWith("before initialization.")) {
    // report a TDZ at e.node; suggest reordering parameter defaults
  }
  throw e;
}

Prevention

When it happens

Trigger: A function parameter default referencing a parameter declared after it: `function f(a = b, b = 2) {}`. Evaluating the default for `a` reads `b` before it is bound.

Common situations: Porting JS code with out-of-order parameter defaults; LLM-generated function signatures that reference later parameters from earlier defaults.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/b764e03826611fa2. Report an issue: GitHub.