{"record":{"id":"adee2fe117793df2","repo":"different-ai/openwork","slug":"switch-case-values-must-be-data-values-in-codemode","errorCode":null,"errorMessage":"Switch case values must be data values in CodeMode.","messagePattern":"Switch case values must be data values in CodeMode\\.","errorType":"exception","errorClass":"InterpreterRuntimeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/interpreter/runtime.ts","lineNumber":916,"sourceCode":"      if (containsOpaqueReference(discriminant)) {\n        throw new InterpreterRuntimeError(\n          \"Switch discriminants must be data values in CodeMode.\",\n          node,\n          \"InvalidDataValue\",\n        )\n      }\n      const cases = getArray(node, \"cases\").map((value, index) => asNode(value, `cases[${index}]`))\n      let defaultIndex: number | undefined\n      let selected: number | undefined\n      for (const [index, branch] of cases.entries()) {\n        const test = getOptionalNode(branch, \"test\")\n        if (!test) {\n          defaultIndex = index\n          continue\n        }\n        const candidate = yield* self.evaluateExpression(test)\n        if (containsOpaqueReference(candidate)) {\n          throw new InterpreterRuntimeError(\n            \"Switch case values must be data values in CodeMode.\",\n            test,\n            \"InvalidDataValue\",\n          )\n        }\n        if (candidate === discriminant) {\n          selected = index\n          break\n        }\n      }\n      const start = selected ?? defaultIndex\n      if (start === undefined) return { kind: \"none\" } satisfies StatementResult\n      for (let index = start; index < cases.length; index += 1) {\n        for (const statementValue of getArray(cases[index]!, \"consequent\")) {\n          const result = yield* self.evaluateStatement(asNode(statementValue, \"consequent\"))\n          if (result.kind === \"break\") return { kind: \"none\" } satisfies StatementResult\n          if (result.kind === \"return\" || result.kind === \"continue\") return result\n          if (result.kind === \"value\") self.lastValue = result.value","sourceCodeStart":898,"sourceCodeEnd":934,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/interpreter/runtime.ts#L898-L934","documentation":"Every `case` test value in a CodeMode switch must also be a pure data value. After evaluating a case expression, the interpreter checks it with containsOpaqueReference and throws InvalidDataValue at the case node if the candidate value carries an opaque reference. This keeps case matching strictly value-based (=== on data), never reference-based.","triggerScenarios":"A `case someExpression:` where the expression evaluates to an opaque reference — e.g. `case someFn:` comparing against a function, or `case tools.fs.read:` comparing against a tool handle.","commonSituations":"LLM-generated CodeMode code that lists function or tool references as case labels, a pattern valid in real JavaScript but rejected by the sandbox.","solutions":["Use data literals (strings/numbers) as case values and map them to actions afterward.","Convert the reference to a comparable data value (e.g. `.name`, `.id`) in both the discriminant and the case.","Replace the switch with if/else using explicit reference equality when identity checks are intended."],"exampleFix":"// before\nswitch (name) {\n  case fsReadTool: ... }\n// after\nswitch (name) {\n  case \"fs.read\": ... }","handlingStrategy":"validation","validationCode":"// validate every case expression result is data before matching\nfor (const c of caseValues) {\n  if (typeof c === \"function\" || (c && typeof c === \"object\" && c.__opaque)) {\n    throw new Error(\"case values must be data values\");\n  }\n}","typeGuard":"const isPrimitiveCase = (v: unknown): v is string | number | boolean | null =>\n  v === null || [\"string\", \"number\", \"boolean\"].includes(typeof v);","tryCatchPattern":"try {\n  interpret(src);\n} catch (e) {\n  if (e instanceof InterpreterRuntimeError && e.code === \"InvalidDataValue\") {\n    // convert the offending case label to a literal\n  }\n  throw e;\n}","preventionTips":["Use string/number literals as case labels only.","Map case labels to actions after the switch, not via references in labels.","Keep tool/function references out of switch heads entirely."],"tags":["codemode","interpreter","switch-statement","opaque-reference"],"backgroundTag":"non-serializable-value-in-sandbox","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}