{"record":{"id":"40d4b846b076badd","repo":"can1357/oh-my-pi","slug":"openai-files-api-upload-failed-with-http-respons","errorCode":null,"errorMessage":"OpenAI Files API upload failed with HTTP ${response.status}","messagePattern":"OpenAI Files API upload failed with HTTP (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/provider-files-openai.ts","lineNumber":101,"sourceCode":"\t\t\tform.append(\n\t\t\t\t\"file\",\n\t\t\t\tnew Blob([uploadRequest.bytes], { type: uploadRequest.mimeType }),\n\t\t\t\tfileName(uploadRequest),\n\t\t\t);\n\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await request(OPENAI_FILES_URL, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { Authorization: authorization },\n\t\t\t\t\tbody: form,\n\t\t\t\t\tsignal: uploadRequest.signal,\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\"OpenAI Files API upload request failed\");\n\t\t\t}\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(`OpenAI Files API upload failed with HTTP ${response.status}`);\n\t\t\t}\n\n\t\t\tlet payload: unknown;\n\t\t\ttry {\n\t\t\t\tpayload = await response.json();\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\"OpenAI Files API returned an invalid upload response\");\n\t\t\t}\n\t\t\tconst file = parseOpenAIFileResponse(payload);\n\t\t\tif (file.status === \"error\") throw new Error(\"OpenAI Files API reported that the upload failed\");\n\n\t\t\tconst deleteUrl = `${OPENAI_FILES_URL}/${encodeURIComponent(file.id)}`;\n\t\t\treturn {\n\t\t\t\tprovider: \"openai\",\n\t\t\t\tid: file.id,\n\t\t\t\tmimeType: uploadRequest.mimeType,\n\t\t\t\tbytes: file.bytes,\n\t\t\t\tdelete: {","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/provider-files-openai.ts#L83-L119","documentation":"Thrown when the OpenAI Files API responded but with a non-2xx HTTP status. It means the request reached OpenAI and was rejected — the status code (401 invalid key, 403 forbidden, 413 too large, 429 rate limit, 5xx outage) is interpolated into the message. Unlike error 750, the network round-trip succeeded.","triggerScenarios":"client.upload() receives response.ok === false from POST /v1/files. Typical statuses: 401 (invalid/expired API key), 403 (key lacks files scope or org blocked), 413 (file exceeds size limit), 429 (rate limited), 5xx (OpenAI outage).","commonSituations":"Rotated or revoked OPENAI_API_KEY; uploading an image larger than the Files API limit; hitting org rate limits during batch uploads; OpenAI incident causing 5xx responses.","solutions":["Read the HTTP status in the message: 401/403 → fix the API key and its scopes; 413 → shrink or compress the file; 429 → back off and retry later; 5xx → check status.openai.com","Verify the key is a real OpenAI platform key (not an Azure/OpenRouter key) since this client only targets api.openai.com/v1","Retry only on 429/5xx with exponential backoff; fail fast on 4xx client errors","Capture the response body (it contains an error.code) by calling the API directly with curl for a richer diagnosis"],"exampleFix":"// before: retries everything blindly\nawait client.upload(req);\n// after: classify by HTTP status parsed from the thrown message\ntry {\n  await client.upload(req);\n} catch (err) {\n  const m = /HTTP (\\d{3})/.exec(String(err.message));\n  const status = m ? Number(m[1]) : 0;\n  if (status === 429 || status >= 500) await backoffRetry(() => client.upload(req));\n  else throw err; // 401/403/413 are not retryable\n}","handlingStrategy":"try-catch","validationCode":"// validate credential shape before uploading\nif (!/^sk-[A-Za-z0-9_-]+$/.test(key)) {\n  throw new Error(\"OPENAI_API_KEY does not look like a platform key\");\n}","typeGuard":"function isRetryableHttpStatus(err: unknown): boolean {\n  const m = /HTTP (\\d{3})/.exec(err instanceof Error ? err.message : \"\");\n  if (!m) return false;\n  const s = Number(m[1]);\n  return s === 429 || s >= 500;\n}","tryCatchPattern":"try {\n  await client.upload(req);\n} catch (err) {\n  if (isRetryableHttpStatus(err)) await withBackoff(() => client.upload(req));\n  else throw err; // 401/403/413 need config/data changes, not retries\n}","preventionTips":["Verify the API key with a cheap GET /v1/models call at startup","Keep image payloads under the Files API size limit; compress before upload","Back off on 429 instead of hammering the API","Watch status.openai.com during incidents before assuming client error"],"tags":["http","openai","upload","api-error"],"backgroundTag":"http-api-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}