can1357/oh-my-pi · error

${destination} returned an invalid response

Error message

${destination} returned an invalid response

What it means

Image-host uploaders parse the HTTP response body and require it to be a JSON object (not an array, null, or primitive). responseRecord enforces this shape; anything else yields this error naming the destination. It protects downstream field access which assumes a record.

Source

Thrown at packages/coding-agent/src/blob-broker/uploaders-image-hosts.ts:31

	requireCredential,
} from "./uploader-runtime";

const IMGUR_UPLOAD_URL = "https://api.imgur.com/3/upload";
const IMAGESHACK_UPLOAD_URL = "https://api.imageshack.com/v2/images";
const FLICKR_UPLOAD_URL = "https://up.flickr.com/services/upload/";
const FLICKR_REST_URL = "https://api.flickr.com/services/rest";
const VGYME_UPLOAD_URL = "https://vgy.me/upload";

interface FlickrOAuthCredentials {
	consumerKey: string;
	consumerSecret: string;
	token: string;
	tokenSecret: string;
}

function responseRecord(value: unknown, destination: BlobDestinationId): Record<string, unknown> {
	if (!value || typeof value !== "object" || Array.isArray(value)) {
		throw new Error(`${destination} returned an invalid response`);
	}
	return value as Record<string, unknown>;
}

async function jsonResponse(response: Response, destination: BlobDestinationId): Promise<Record<string, unknown>> {
	await expectOk(response, destination);
	let value: unknown;
	try {
		value = await response.json();
	} catch {
		throw new Error(`${destination} returned invalid JSON`);
	}
	return responseRecord(value, destination);
}

function nestedRecord(
	record: Record<string, unknown>,
	key: string,

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the raw response body (response.text()) to see what the host actually returned
  2. Verify the destination's API version/endpoint is still the one expected by this uploader
  3. Look for a documented error payload in the body (rate limit, auth failure) and fix the credentials or quota
  4. Wrap upload calls in try-catch and fall back to another image host
Defensive patterns

Strategy: validation

Validate before calling

const body = await response.text();
let parsed;
try { parsed = JSON.parse(body); } catch { throw new Error("non-JSON body: " + body.slice(0, 200)); }
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("response is not a JSON object");

Type guard

function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

Try / catch

try {
  const pub = await broker.publish(request);
} catch (err) {
  if (err.message.endsWith("returned an invalid response")) {
    logger.warn("host returned non-object JSON", { destination: err.message.split(" ")[0] });
    return fallbackUploader.publish(request);
  }
  throw err;
}

Prevention

When it happens

Trigger: An upload endpoint returns an array (e.g. a list of errors), a JSON scalar (string/number), HTML passed off as JSON, or an empty body that parses to null.

Common situations: Host API changed response shape; hitting a rate-limit or error page returning a top-level array; misconfigured endpoint returning HTML with 200; CDN intercepting the request with a non-object body.

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.

Related errors


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