{"record":{"id":"a14372a0419afb66","repo":"nexu-io/open-design","slug":"openrouter-image-response-missing-image-url-url","errorCode":null,"errorMessage":"openrouter image response missing image_url.url: ${truncate(text, 200)}","messagePattern":"openrouter image response missing image_url\\.url: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/media/index.ts","lineNumber":1892,"sourceCode":"  try {\n    data = JSON.parse(text);\n  } catch {\n    throw new Error(`openrouter image non-JSON response: ${truncate(text, 200)}`);\n  }\n\n  // Extract the first generated image from the response.\n  const images: any[] | undefined =\n    data?.choices?.[0]?.message?.images;\n  if (!images || images.length === 0) {\n    throw new Error(\n      `openrouter image response contained no images for model ${wireModel}: `\n      + truncate(text, 200),\n    );\n  }\n\n  const dataUrl: string | undefined = images[0]?.image_url?.url;\n  if (!dataUrl) {\n    throw new Error(\n      `openrouter image response missing image_url.url: ${truncate(text, 200)}`,\n    );\n  }\n\n  // Strip the data URL prefix (e.g. \"data:image/png;base64,\") and\n  // decode the remaining base64 payload.\n  const b64Match = dataUrl.match(/^data:image\\/[^;]+;base64,(.+)$/s);\n  let bytes: Buffer;\n  if (b64Match) {\n    bytes = Buffer.from(b64Match[1]!, 'base64');\n  } else if (dataUrl.startsWith('http')) {\n    // Some models may return a plain URL instead of inline base64.\n    const imgResp = await fetch(dataUrl, withMediaRequestInit(ctx));\n    if (!imgResp.ok) throw new Error(`openrouter image download ${imgResp.status}`);\n    bytes = Buffer.from(await imgResp.arrayBuffer());\n  } else {\n    // Assume raw base64 without prefix.\n    bytes = Buffer.from(dataUrl, 'base64');","sourceCodeStart":1874,"sourceCodeEnd":1910,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/media/index.ts#L1874-L1910","documentation":"Thrown when the images array has at least one entry but images[0].image_url.url is missing. OpenRouter's contract puts the data URL or hosted URL under `image_url.url`; a present image object without that field means the provider returned a partial or differently-shaped image entry.","triggerScenarios":"Underlying provider returned an image object with only metadata (e.g. a revised_prompt or a moderation flag), OpenRouter changed the field name, or the entry is a placeholder/error object inside the images array.","commonSituations":"Schema drift on OpenRouter's side, an image model returning a content-filter object in the images slot, or a half-finished response from a provider incident.","solutions":["Inspect images[0] — its keys reveal whether the field was renamed or whether it is a moderation/metadata object.","Retry once for transient partial responses.","If the field was renamed, update the dataUrl extraction at apps/daemon/src/media/index.ts:1890.","Switch to a different image-capable model on OpenRouter if the chosen one consistently returns this shape."],"exampleFix":"// before\nconst dataUrl = images[0]?.image_url?.url;\nif (!dataUrl) {\n  throw new Error(`openrouter image response missing image_url.url: ${truncate(text, 200)}`);\n}\n\n// after — expose the malformed entry\nconst first = images[0];\nconst dataUrl = first?.image_url?.url;\nif (!dataUrl) {\n  throw new Error(\n    `openrouter image entry missing image_url.url: ${truncate(JSON.stringify(first), 200)}`,\n  );\n}","handlingStrategy":"type-guard","validationCode":"// Accept a few aliases and surface the malformed entry\nfunction extractOpenRouterDataUrl(first: any, fullText: string): string {\n  const url = first?.image_url?.url || first?.url || first?.image;\n  if (typeof url === 'string' && url) return url;\n  throw new Error(`openrouter image entry missing image_url.url: ${truncate(JSON.stringify(first), 200)}`);\n}","typeGuard":"interface OpenRouterImageEntry { image_url?: { url?: string }; url?: string; image?: string }\nfunction isOpenRouterImageEntry(v: unknown): v is OpenRouterImageEntry {\n  return typeof v === 'object' && v !== null && (\n    typeof (v as any).image_url?.url === 'string' ||\n    typeof (v as any).url === 'string' ||\n    typeof (v as any).image === 'string'\n  );\n}","tryCatchPattern":"const first = images[0];\nlet dataUrl: string;\ntry {\n  dataUrl = extractOpenRouterDataUrl(first, text);\n} catch (e) {\n  ctx.onProviderRequestSettled?.({ providerId: 'openrouter', ok: false, error: String(e) });\n  throw e;\n}","preventionTips":["Accept common field aliases when extracting the image URL to absorb minor schema drift.","Log the unrecognized entry keys when extraction fails.","Pin to a stable OpenRouter model slug rather than a fast-moving alias.","Retry once for transient partial responses."],"tags":["openrouter","image-generation","response-shape","provider-api"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}