{"record":{"id":"d2403e54ccbb22b7","repo":"coleam00/Archon","slug":"codex-structured-output-not-json","errorCode":"codex.structured_output_not_json","errorMessage":"⚠️ Structured output requested but Codex returned non-JSON text. Downstream $nodeId.output.field references may not evaluate correctly.","messagePattern":"⚠️ Structured output requested but Codex returned non-JSON text\\. Downstream \\$nodeId\\.output\\.field references may not evaluate correctly\\.","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/providers/src/codex/provider.ts","lineNumber":800,"sourceCode":"\n    if (event.type === 'turn.completed') {\n      getLog().debug('turn_completed');\n      const usage = extractUsageFromCodexEvent(event as TurnCompletedEvent);\n\n      // Codex returns structured output inline in agent_message text.\n      // Normalize: parse as JSON and put on structuredOutput so the\n      // dag-executor can handle all providers uniformly.\n      let structuredOutput: unknown;\n      if (hasOutputFormat && accumulatedText) {\n        try {\n          structuredOutput = JSON.parse(accumulatedText);\n          getLog().debug('codex.structured_output_parsed');\n        } catch {\n          getLog().warn(\n            { outputPreview: accumulatedText.slice(0, 200) },\n            'codex.structured_output_not_json'\n          );\n          yield {\n            type: 'system',\n            content:\n              '⚠️ Structured output requested but Codex returned non-JSON text. ' +\n              'Downstream $nodeId.output.field references may not evaluate correctly.',\n          };\n        }\n      }\n\n      yield {\n        type: 'result',\n        sessionId: resolvedThreadId ?? undefined,\n        tokens: usage,\n        ...(structuredOutput !== undefined ? { structuredOutput } : {}),\n      };\n      return;\n    }\n  }\n","sourceCodeStart":782,"sourceCodeEnd":818,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/providers/src/codex/provider.ts#L782-L818","documentation":"Codex was invoked with structured output requested, but the provider's accumulated response text failed JSON.parse. Since downstream workflow nodes may reference `$nodeId.output.field`, the provider emits a system message warning that those references may not evaluate. It is a degraded-output warning, not a thrown exception.","triggerScenarios":"streamCodexEvents (called by sendQuery) accumulates Codex text output, tries JSON.parse at the end, and the catch block fires because the model returned prose, markdown fences, or truncated JSON despite the structured-output request.","commonSituations":"Model ignored the JSON instruction and answered conversationally; response wrapped the JSON in ```json fences or added commentary; long outputs got truncated mid-object; model version change altered formatting behavior.","solutions":["Re-run the node with an explicit instruction to output only raw JSON with no fences or commentary","Validate/repair the text before relying on it: strip code fences and retry JSON.parse downstream","Use the provider's native structured-output/JSON mode instead of prompt-only requests","Treat the system message as a failure signal and gate downstream $nodeId.output.* references on a schema-validated parse"],"exampleFix":"// before: parse accumulated text directly\nconst data = JSON.parse(accumulatedText);\n// after: tolerate fences, validate shape\nconst raw = accumulatedText.replace(/^```(?:json)?\\n?|\\n?```$/g, '').trim();\nconst data = JSON.parse(raw);\nif (typeof data !== 'object' || data === null) throw new Error('codex structured output is not an object');","handlingStrategy":"validation","validationCode":"function isUsableStructuredOutput(text: string): boolean {\n  try {\n    const v = JSON.parse(text.replace(/^```(?:json)?\\n?|\\n?```$/g, '').trim());\n    return typeof v === 'object' && v !== null;\n  } catch { return false; }\n}","typeGuard":"function isRecord(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"let parsed: Record<string, unknown> | null = null;\ntry {\n  parsed = JSON.parse(raw.replace(/^```(?:json)?\\n?|\\n?```$/g, '').trim());\n} catch (e) {\n  // fall back: re-run the node or surface a typed failure instead of reading output.field\n  parsed = null;\n}","preventionTips":["Instruct the model to emit raw JSON only, with no markdown fences or commentary","Prefer the provider's native structured-output/JSON mode over prompt-only enforcement","Schema-validate parsed output before consuming $nodeId.output.* references","Watch for the codex.structured_output_not_json system message and gate downstream nodes on it"],"tags":["codex","structured-output","json-parsing","providers"],"backgroundTag":"structured-output-not-json","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}