{"record":{"id":"e76159b5a8736fe3","repo":"can1357/oh-my-pi","slug":"openai-files-api-returned-an-invalid-upload-respon","errorCode":null,"errorMessage":"OpenAI Files API returned an invalid upload response","messagePattern":"OpenAI Files API returned an invalid upload response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/provider-files-openai.ts","lineNumber":40,"sourceCode":"\t\treturn (\n\t\t\tbaseUrl.protocol === \"https:\" &&\n\t\t\tbaseUrl.hostname === \"api.openai.com\" &&\n\t\t\tbaseUrl.port === \"\" &&\n\t\t\tbaseUrl.username === \"\" &&\n\t\t\tbaseUrl.password === \"\" &&\n\t\t\tbaseUrl.search === \"\" &&\n\t\t\tbaseUrl.hash === \"\" &&\n\t\t\tpathname === \"/v1\"\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction parseOpenAIFileResponse(payload: unknown): OpenAIFileResponse {\n\tconst file = payload as Partial<OpenAIFileResponse> | null;\n\tif (file === null || typeof file !== \"object\") {\n\t\tthrow new Error(\"OpenAI Files API returned an invalid upload response\");\n\t}\n\n\tconst { id, bytes, status } = file;\n\tif (typeof id !== \"string\" || id.trim().length === 0) {\n\t\tthrow new Error(\"OpenAI Files API upload response is missing a file id\");\n\t}\n\tif (typeof bytes !== \"number\" || !Number.isSafeInteger(bytes) || bytes < 0) {\n\t\tthrow new Error(\"OpenAI Files API upload response has an invalid byte count\");\n\t}\n\tif (status !== \"uploaded\" && status !== \"processed\" && status !== \"error\") {\n\t\tthrow new Error(\"OpenAI Files API upload response has an invalid status\");\n\t}\n\treturn { id, bytes, status };\n}\n\nfunction fileName(request: ProviderFileUploadRequest): string {\n\tconst preferred = request.filename?.trim().replaceAll(\"\\\\\", \"/\").split(\"/\").pop();\n\treturn preferred && preferred !== \".\" && preferred !== \"..\" ? preferred : \"image\";","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/provider-files-openai.ts#L22-L58","documentation":"Thrown by parseOpenAIFileResponse when the JSON body returned by the OpenAI Files API after an upload is not an object (null, array, string, etc.). The library validates the shape of the upload response before extracting id/bytes/status, since a non-object body can never carry a usable file descriptor.","triggerScenarios":"Calling upload() (via file → parseOpenAIFileResponse) when the OpenAI Files API response body parses to null or a non-object — e.g. an HTML error page that somehow parses, a proxy returning an unexpected body, or a response interceptor returning the wrong shape.","commonSituations":"Corporate proxy or captive portal returning HTML instead of JSON; hitting a mirror/relay that changes the response envelope; OpenAI returning an error payload shaped differently than expected (e.g. {error: {...}} top-level); mocking fetch in tests with a non-object payload.","solutions":["Log the raw response body to see what was actually returned; this error means the body wasn't an object.","Check that you are hitting the official OpenAI endpoint and not a proxy that rewrites responses.","Verify the model/credential path — an auth redirect or gateway error page can masquerade as a response body.","If using a custom fetchImpl, ensure it returns the parsed JSON body, not a Response wrapper or string.","Check OpenAI status page for incidents producing alternate error responses."],"exampleFix":"// before: blind upload with custom fetch\nconst client = createOpenAIFileClient(model, key, myFetch);\n// after: verify fetchImpl returns parsed JSON object\nconst myFetch: FetchImpl = async (url, init) => {\n  const res = await fetch(url, init);\n  const body = await res.json();\n  if (body === null || typeof body !== \"object\") throw new Error(`unexpected body: ${typeof body}`);\n  return body;\n};","handlingStrategy":"type-guard","validationCode":"const body = await res.clone().json();\nif (body === null || typeof body !== \"object\" || Array.isArray(body)) {\n  throw new Error(`OpenAI returned non-object body: ${String(await res.clone().text()).slice(0, 200)}`);\n}","typeGuard":"function isObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const handle = await openaiClient.upload(request);\n} catch (err) {\n  if (String(err?.message).includes(\"invalid upload response\")) {\n    // response body wasn't an object — inspect raw body via logging proxy\n    throw new Error(\"OpenAI endpoint/proxy returned a non-JSON or non-object body; check gateway\");\n  }\n  throw err;\n}","preventionTips":["Log raw response bodies on upload failure for diagnosis","Bypass intercepting proxies when testing file uploads","Make custom fetchImpl wrappers return the parsed JSON object, not a wrapper","Check OpenAI status page when error payloads suddenly change shape"],"tags":["validation","openai","file-upload","response-parsing","schema-validation-failed"],"backgroundTag":"invalid-api-response-shape","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}