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

  1. Log the raw response body to see what was actually returned; this error means the body wasn't an object.
  2. Check that you are hitting the official OpenAI endpoint and not a proxy that rewrites responses.
  3. Verify the model/credential path — an auth redirect or gateway error page can masquerade as a response body.
  4. If using a custom fetchImpl, ensure it returns the parsed JSON body, not a Response wrapper or string.
  5. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e76159b5a8736fe3. Report an issue: GitHub.