{"record":{"id":"96c6b6b03177cde5","repo":"nexu-io/open-design","slug":"openai-resp-status-await-resp-text-catch","errorCode":null,"errorMessage":"openai ${resp.status}: ${await resp.text().catch(() => '')}","messagePattern":"openai (.+?): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/memory-llm.ts","lineNumber":847,"sourceCode":"            ? { 'APP-Code': AIHUBMIX_APP_CODE }\n            : {}),\n        },\n        body: JSON.stringify({\n          model: provider.model,\n          response_format: { type: 'json_object' },\n          messages: [\n            { role: 'system', content: system },\n            { role: 'user', content: user },\n          ],\n        }),\n        signal: withTimeout(FETCH_TIMEOUT_MS),\n      },\n    );\n  } catch (err) {\n    throw new Error(describeFetchError(err));\n  }\n  if (!resp.ok) {\n    throw new Error(`openai ${resp.status}: ${await resp.text().catch(() => '')}`);\n  }\n  const json = await resp.json();\n  return json?.choices?.[0]?.message?.content ?? '';\n}\n\n// Azure OpenAI speaks the same chat-completions JSON as OpenAI, but on\n// a per-deployment URL and with `api-key:` instead of `Authorization:`.\n// `provider.model` here is the Azure deployment name (the user typed it\n// into the model field — that's what the chat picker calls \"Deployment\n// (Model)\" too), not the underlying model family.\nasync function callAzure(provider, system, user) {\n  const base = String(provider.baseUrl || '').replace(/\\/+$/, '');\n  const deployment = encodeURIComponent(provider.model);\n  const apiVersion = encodeURIComponent(\n    provider.apiVersion || PROVIDER_DEFAULTS.azure.apiVersion,\n  );\n  const url = `${base}/openai/deployments/${deployment}/chat/completions?api-version=${apiVersion}`;\n  let resp;","sourceCodeStart":829,"sourceCodeEnd":865,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/memory-llm.ts#L829-L865","documentation":"The OpenAI Chat Completions API returned a non-2xx HTTP status during the memory-LLM extraction call. The error includes the status code and raw response body. This is the callOpenAI path in the daemon's automatic memory extractor.","triggerScenarios":"Invalid or expired API key (401/403); rate limiting (429); model name not available; quota exceeded; malformed request payload; baseUrl pointing to a wrong endpoint.","commonSituations":"API key rotated without updating config; wrong baseUrl (e.g. pointing to Azure endpoint without the OpenAI path); model deprecated; hitting rate limits during batch extraction; organization billing issues.","solutions":["Check the API key is valid and has quota","Verify provider.model is a model available on the account","Confirm provider.baseUrl points to the correct OpenAI-compatible endpoint with /chat/completions path","Inspect the response body for the specific error code","Retry after a delay if rate-limited (429)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const text = await callOpenAI(provider, system, user);\n} catch (err) {\n  if (err.message.startsWith('openai ')) {\n    const status = parseInt(err.message.split(' ')[1], 10);\n    if (status === 429) {\n      await sleep(backoffMs);\n      return callOpenAI(provider, system, user);\n    }\n    if (status === 401 || status === 403) {\n      throw new Error('OpenAI API key is invalid or lacks permission');\n    }\n  }\n  throw err;\n}","preventionTips":["Verify the OpenAI API key and organization billing status","Confirm provider.model is an available model identifier","Ensure provider.baseUrl includes the correct /chat/completions path or base origin","Handle 429 responses with exponential backoff"],"tags":["openai","llm","http","memory-extraction","network"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}