can1357/oh-my-pi · error · LegacyDestinationError
the upload endpoint returned invalid JSON
Error message
the upload endpoint returned invalid JSON
What it means
This LegacyDestinationError is thrown by jsonObject() when `response.json()` fails — i.e. the upload endpoint's HTTP response body is not valid JSON (or the body was already consumed). The library expects every legacy JSON-based uploader response to parse as JSON, and wraps the SyntaxError as `cause`.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-legacy.ts:129
}
function firstString(record: Readonly<Record<string, unknown>>, keys: readonly string[]): string | undefined {
for (const key of keys) {
const value = record[key];
if (typeof value === "string" && value.trim()) return value.trim();
}
return undefined;
}
async function jsonObject(
destination: BlobDestinationId,
response: Response,
): Promise<Readonly<Record<string, unknown>>> {
let value: unknown;
try {
value = await response.json();
} catch (error) {
throw new LegacyDestinationError(destination, "the upload endpoint returned invalid JSON", error);
}
const record = objectValue(value);
for (const _ in record) return record;
throw new LegacyDestinationError(destination, "the upload endpoint returned an invalid JSON object");
}
function directJsonUrl(destination: BlobDestinationId, record: Readonly<Record<string, unknown>>, base: URL): string {
const nested = objectValue(record.response);
const raw =
firstString(record, ["direct_url", "directUrl", "url", "URL"]) ??
firstString(nested, ["direct_url", "directUrl", "url", "URL"]);
if (!raw) throw new LegacyDestinationError(destination, "the upload response did not include a direct image URL");
return httpUrl(destination, raw, base);
}
function basicAuthorization(username: string, password: string): string {
return `Basic ${Buffer.from(`${username}:${password}`, "utf8").toString("base64")}`;
}View on GitHub (pinned to 9690622007)
Solutions
- Log the raw response body and status before parsing to see what the server actually sent
- Fix authentication so the endpoint stops returning HTML error/login pages
- Ensure the custom endpoint always replies with a JSON object (even on errors)
- Check for CDN/WAF challenge pages (Cloudflare) and allowlist the client
Defensive patterns
Strategy: try-catch
Type guard
function looksLikeJson(response: Response): boolean {
const ct = response.headers.get("content-type") ?? "";
return ct.includes("application/json");
} Try / catch
try {
const result = await uploader.upload(request);
} catch (err) {
if (err instanceof Error && err.message.includes("returned invalid JSON")) {
console.error("cause:", err.cause); // SyntaxError details + check status/body
} else throw err;
} Prevention
- Check response status and content-type before assuming JSON
- Watch for HTML error/login/Cloudflare-challenge pages from misconfigured endpoints
- Ensure custom endpoints always emit a JSON body even on errors
- Test endpoints under failure conditions (403, 500) to see what body they produce
When it happens
Trigger: The endpoint returns HTML (error page, login page, Cloudflare challenge), an empty body, plain text, or truncated JSON; a 5xx/403 page is returned with text/html content-type; the response stream was interrupted mid-body; called from the `data` helper on JSON-based uploaders.
Common situations: Self-hosted replacement endpoint returning its framework's HTML 404/500 page; auth failure redirecting to an HTML login page; rate-limit/CDN block pages; proxy returning non-JSON errors.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- the upload endpoint returned an invalid JSON object
- the upload response did not include a direct image URL
- the upload response did not contain a valid direct URL
- the upload response URL must use HTTP or HTTPS
- Gemini Files API ${context} response is not valid JSON
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3e0c94d35f66650d.
Report an issue: GitHub.