can1357/oh-my-pi · error
OpenAI Files API returned an invalid upload response
Error message
OpenAI Files API returned an invalid upload response
What it means
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.
Source
Thrown at packages/coding-agent/src/blob-broker/provider-files-openai.ts:40
return (
baseUrl.protocol === "https:" &&
baseUrl.hostname === "api.openai.com" &&
baseUrl.port === "" &&
baseUrl.username === "" &&
baseUrl.password === "" &&
baseUrl.search === "" &&
baseUrl.hash === "" &&
pathname === "/v1"
);
} catch {
return false;
}
}
function parseOpenAIFileResponse(payload: unknown): OpenAIFileResponse {
const file = payload as Partial<OpenAIFileResponse> | null;
if (file === null || typeof file !== "object") {
throw new Error("OpenAI Files API returned an invalid upload response");
}
const { id, bytes, status } = file;
if (typeof id !== "string" || id.trim().length === 0) {
throw new Error("OpenAI Files API upload response is missing a file id");
}
if (typeof bytes !== "number" || !Number.isSafeInteger(bytes) || bytes < 0) {
throw new Error("OpenAI Files API upload response has an invalid byte count");
}
if (status !== "uploaded" && status !== "processed" && status !== "error") {
throw new Error("OpenAI Files API upload response has an invalid status");
}
return { id, bytes, status };
}
function fileName(request: ProviderFileUploadRequest): string {
const preferred = request.filename?.trim().replaceAll("\\", "/").split("/").pop();
return preferred && preferred !== "." && preferred !== ".." ? preferred : "image";View on GitHub (pinned to 9690622007)
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.
Example fix
// before: blind upload with custom fetch
const client = createOpenAIFileClient(model, key, myFetch);
// after: verify fetchImpl returns parsed JSON object
const myFetch: FetchImpl = async (url, init) => {
const res = await fetch(url, init);
const body = await res.json();
if (body === null || typeof body !== "object") throw new Error(`unexpected body: ${typeof body}`);
return body;
}; Defensive patterns
Strategy: type-guard
Validate before calling
const body = await res.clone().json();
if (body === null || typeof body !== "object" || Array.isArray(body)) {
throw new Error(`OpenAI returned non-object body: ${String(await res.clone().text()).slice(0, 200)}`);
} Type guard
function isObject(v: unknown): v is Record<string, unknown> {
return typeof v === "object" && v !== null && !Array.isArray(v);
} Try / catch
try {
const handle = await openaiClient.upload(request);
} catch (err) {
if (String(err?.message).includes("invalid upload response")) {
// response body wasn't an object — inspect raw body via logging proxy
throw new Error("OpenAI endpoint/proxy returned a non-JSON or non-object body; check gateway");
}
throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- OpenAI Files API upload response has an invalid byte count
- OpenAI Files API upload response is missing a file id
- OpenAI Files API upload response has an invalid status
- OpenAI Responses compaction input contains a non-object item
- OpenAI stream response has no body (status ${response.status
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e76159b5a8736fe3.
Report an issue: GitHub.