{"record":{"id":"ef967a241e011653","repo":"tinyhumansai/openhuman","slug":"openai-response-did-not-contain-output-text","errorCode":null,"errorMessage":"OpenAI response did not contain output text","messagePattern":"OpenAI response did not contain output text","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/release/generate-release-notes.mjs","lineNumber":514,"sourceCode":"    clearTimeout(timeout);\n  }\n\n  const body = await response.text();\n  let json = null;\n  try {\n    json = JSON.parse(body);\n  } catch {\n    // Keep the raw body in the error below.\n  }\n\n  if (!response.ok) {\n    const message = json?.error?.message || body;\n    throw new Error(`OpenAI Responses API failed (${response.status}): ${message}`);\n  }\n\n  const text = extractResponseText(json);\n  if (!text) {\n    throw new Error('OpenAI response did not contain output text');\n  }\n  return text;\n}\n\nexport function renderDeterministicNotes({ title, payload }) {\n  const newContributors = payload.contributors.filter((contributor) => contributor.isNew);\n  const newContributorsSection = newContributors.length\n    ? `\n## New Contributors 🌟\n\n${newContributors.map((contributor) => renderNewContributorLine(contributor, payload.pullRequests)).join('\\n')}\n\nHope you join the Discord for exclusive roles and contributor rewards!\n`\n    : '';\n  const contributorLinks = payload.contributors.map((contributor) => {\n    const prList = contributor.prs.map((number) => `#${number}`).join(', ');\n    return `- ${contributor.name}${prList ? ` (${prList})` : ''}`;","sourceCodeStart":496,"sourceCodeEnd":532,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/release/generate-release-notes.mjs#L496-L532","documentation":"OpenAI returned HTTP 2xx but extractResponseText() found no usable text: output_text is not a string and no output[].content[].text entries exist, so there is nothing to turn into release notes. The parser is intentionally loose, so schema drift or non-text responses surface here rather than as a parse crash.","triggerScenarios":"The model responded with only non-text output items (reasoning-only, refusal phrasing, or an empty output array); the Responses API changed its item shape; a truncated response dropped the text items.","commonSituations":"A new default model emitting different item structures; rare one-off model behavior; API evolution after an OpenAI deploy — the request succeeded but the shape is not what the script extracts.","solutions":["Re-run once — usually a one-off model behavior","Capture the request with --dry-run and replay it (curl) to inspect the raw response shape","Fall back to --no-ai for deterministic notes","Pin --model to a variant known to return plain text output"],"exampleFix":"# before\nnode scripts/release/generate-release-notes.mjs --from v1.2.3   # 200 OK, but 'did not contain output text'\n\n# after — deterministic output, no OpenAI dependency\nnode scripts/release/generate-release-notes.mjs --from v1.2.3 --no-ai","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"markdown=$(node scripts/release/generate-release-notes.mjs --from \"$FROM\" 2>&1) || \\\n  markdown=$(node scripts/release/generate-release-notes.mjs --from \"$FROM\" --no-ai 2>&1) || \\\n  { echo 'both AI and deterministic generation failed' >&2; exit 1; }\nprintf '%s\\n' \"$markdown\"","preventionTips":["keep --no-ai as the documented fallback in every runbook","pin --model so output-item shapes do not drift under you","use --dry-run to capture request payloads for replay during incidents"],"tags":["openai","parsing","release-notes","api-contract"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}