{"record":{"id":"a318685b28db6530","repo":"can1357/oh-my-pi","slug":"destination-response-did-not-include-key","errorCode":null,"errorMessage":"${destination} response did not include ${key}","messagePattern":"(.+?) response did not include (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-image-hosts.ts","lineNumber":58,"sourceCode":"\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,\n\tdestination: BlobDestinationId,\n): Record<string, unknown> {\n\treturn responseRecord(record[key], destination);\n}\n\nfunction requiredString(record: Record<string, unknown>, key: string, destination: BlobDestinationId): string {\n\tconst value = record[key];\n\tif (typeof value !== \"string\" || value.length === 0) {\n\t\tthrow new Error(`${destination} response did not include ${key}`);\n\t}\n\treturn value;\n}\n\nfunction directUrl(value: string, destination: BlobDestinationId): string {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new Error(`${destination} returned an invalid image URL`);\n\t}\n\tif (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n\t\tthrow new Error(`${destination} returned an invalid image URL`);\n\t}\n\treturn url.href;\n}\n\nfunction createImgurUploader(config: DestinationRuntimeConfig): BlobUploader {","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-image-hosts.ts#L40-L76","documentation":"requiredString asserts that a key in the parsed response record is a non-empty string (used for `id` and `url`). If the key is missing, null, another type, or an empty string, this error is thrown naming the destination and the expected key. It signals the host's response did not contain a required field.","triggerScenarios":"Response object lacks the expected key; the key holds a number/null/array instead of a string; the key holds an empty string after upload.","commonSituations":"Image host changed its JSON schema (renamed or nested the field); upload 'succeeded' per status but the resource was quarantined so no URL was issued; partial/mock responses in tests.","solutions":["Log the full response object to see which key is absent and what shape the host now uses","Update expectations if the host renamed the field (schema drift)","Treat repeated occurrences as an API change and pin/upgrade the destination integration","Catch and fall back to another image host"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"const payload = await response.json();\nif (typeof payload?.url !== \"string\" || payload.url.length === 0) throw new Error(\"host response missing url\");","typeGuard":"function hasStringField(record, key) {\n  return typeof record?.[key] === \"string\" && record[key].length > 0;\n}","tryCatchPattern":"try {\n  const pub = await broker.publish(request);\n} catch (err) {\n  if (err.message.includes(\"response did not include\")) {\n    logger.warn(\"host response schema drift\", { destination, message: err.message });\n    return fallbackUploader.publish(request);\n  }\n  throw err;\n}","preventionTips":["Log the full response object on failure to detect schema drift","Track image host API changelogs for renamed/nested fields","Validate host responses once in an integration smoke test","Fall back to another host rather than treating one bad response as fatal"],"tags":["validation","schema-mismatch","image-host","missing-field"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}