{"record":{"id":"a55a93a52450f059","repo":"can1357/oh-my-pi","slug":"destination-returned-an-invalid-response","errorCode":null,"errorMessage":"${destination} returned an invalid response","messagePattern":"(.+?) returned an invalid response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-image-hosts.ts","lineNumber":31,"sourceCode":"\trequireCredential,\n} from \"./uploader-runtime\";\n\nconst IMGUR_UPLOAD_URL = \"https://api.imgur.com/3/upload\";\nconst IMAGESHACK_UPLOAD_URL = \"https://api.imageshack.com/v2/images\";\nconst FLICKR_UPLOAD_URL = \"https://up.flickr.com/services/upload/\";\nconst FLICKR_REST_URL = \"https://api.flickr.com/services/rest\";\nconst VGYME_UPLOAD_URL = \"https://vgy.me/upload\";\n\ninterface FlickrOAuthCredentials {\n\tconsumerKey: string;\n\tconsumerSecret: string;\n\ttoken: string;\n\ttokenSecret: string;\n}\n\nfunction responseRecord(value: unknown, destination: BlobDestinationId): Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(`${destination} returned an invalid response`);\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nasync function jsonResponse(response: Response, destination: BlobDestinationId): Promise<Record<string, unknown>> {\n\tawait expectOk(response, destination);\n\tlet value: unknown;\n\ttry {\n\t\tvalue = await response.json();\n\t} catch {\n\t\tthrow new Error(`${destination} returned invalid JSON`);\n\t}\n\treturn responseRecord(value, destination);\n}\n\nfunction nestedRecord(\n\trecord: Record<string, unknown>,\n\tkey: string,","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-image-hosts.ts#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the raw response body (response.text()) to see what the host actually returned","Verify the destination's API version/endpoint is still the one expected by this uploader","Look for a documented error payload in the body (rate limit, auth failure) and fix the credentials or quota","Wrap upload calls in try-catch and fall back to another image host"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const body = await response.text();\nlet parsed;\ntry { parsed = JSON.parse(body); } catch { throw new Error(\"non-JSON body: \" + body.slice(0, 200)); }\nif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) throw new Error(\"response is not a JSON object\");","typeGuard":"function isRecord(value) {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}","tryCatchPattern":"try {\n  const pub = await broker.publish(request);\n} catch (err) {\n  if (err.message.endsWith(\"returned an invalid response\")) {\n    logger.warn(\"host returned non-object JSON\", { destination: err.message.split(\" \")[0] });\n    return fallbackUploader.publish(request);\n  }\n  throw err;\n}","preventionTips":["Verify the destination endpoint URL and API version are current","Inspect raw response bodies when integrating a new image host","Use fallback uploaders so a single host's odd payload doesn't break uploads","Check for rate-limit/error pages that return arrays or HTML with 200"],"tags":["json","validation","http-response","image-host"],"backgroundTag":"invalid-json-response","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}