{"record":{"id":"b172ca070e8c420c","repo":"toeverything/AFFiNE","slug":"copilot-prompt-invalid-b172ca","errorCode":"copilot_prompt_invalid","errorMessage":"Structured response is missing output_json","messagePattern":"Structured response is missing output_json","errorType":"exception","errorClass":"CopilotPromptInvalid","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/plugins/copilot/runtime/capability-runtime.ts","lineNumber":319,"sourceCode":"    slot = 'prompt.structured'\n  ) {\n    const contract = requireStructuredOutputContract(responseContract);\n    if (!contract) {\n      throw new CopilotPromptInvalid('Structured schema contract is required');\n    }\n    const { request } = await buildCanonicalNativeStructuredRequest({\n      model: 'route-selected',\n      messages,\n      options,\n      responseContract: contract,\n      attachmentCapability,\n    });\n    const result = (await this.execute(slot, request, cond, options)) as {\n      output_json?: unknown;\n      output_text: string;\n    };\n    if (result.output_json === undefined) {\n      throw new CopilotPromptInvalid(\n        'Structured response is missing output_json'\n      );\n    }\n    return JSON.stringify(\n      llmValidateJsonSchema(request.schema, result.output_json)\n    );\n  }\n\n  async generateStructuredValue(\n    cond: ModelConditions,\n    messages: PromptMessage[],\n    options: CopilotStructuredOptions,\n    responseContract?: RequiredStructuredOutputContract,\n    filter?: ProviderFilter,\n    slot = 'prompt.structured'\n  ) {\n    const contract = requireStructuredOutputContract(responseContract);\n    if (!contract) {","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/copilot/runtime/capability-runtime.ts#L301-L337","documentation":"capability-runtime's structured generation expects the model response to carry output_json; when it is undefined it throws CopilotPromptInvalid (code `copilot_prompt_invalid`, status `invalid_input`) 'Structured response is missing output_json'. The call executed, but the response did not honor the structured-output contract (often only output_text came back).","triggerScenarios":"The chosen model/route ignores or does not support the responseContract (JSON/structured output) built by buildCanonicalNativeStructuredRequest; the provider returned text only; a degraded path dropped the contract; complex schemas make the model fall back to prose.","commonSituations":"Pointing structured prompts at a model without native JSON mode; provider API changes dropping response_format; overly nested/strict JSON schemas that models fail and answer in text; self-hosted gateways that strip response options.","solutions":["Use a model/route that supports native structured output (JSON mode / response contracts)","Verify the responseContract survived request building (not stripped by options overrides or a gateway)","Retry — some providers intermittently omit JSON while succeeding otherwise","Simplify the JSON schema (fewer required fields, less nesting) so the model can satisfy it"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// guard: only request structured output from models that support it\nif (!modelSupportsJsonMode(step.modelId)) {\n  throw new Error('model lacks structured-output support — pick a JSON-capable route');\n}","typeGuard":"function isPromptInvalid(e: unknown): boolean {\n  return (e as { extensions?: { code?: string } })?.extensions?.code === 'copilot_prompt_invalid';\n}","tryCatchPattern":"try {\n  return await generateStructured(contract, messages, options);\n} catch (e) {\n  if (isPromptInvalid(e) && /output_json/.test((e as Error).message)) {\n    await sleep(500);\n    return generateStructured(simplifySchema(contract), messages, options); // retry, simpler schema\n  }\n  throw e;\n}","preventionTips":["Route structured prompts only to models with native JSON/structured output support","Keep JSON schemas shallow with few required fields","Log which model/route produced text-only responses so misrouted models get fixed"],"tags":["copilot","structured-output","llm","json-schema","prompt"],"backgroundTag":"llm-structured-output-invalid","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}