{"record":{"id":"3471301e74b99b4b","repo":"Mintplex-Labs/anything-llm","slug":"image-edit-failed-res-status-body-res-s","errorCode":null,"errorMessage":"Image edit failed (${res.status}): ${body || res.statusText}","messagePattern":"Image edit failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/utils/ImageGenerators/base.js","lineNumber":97,"sourceCode":"        this.imageFieldName(images.length),\n        new Blob([images[i]], { type: \"image/png\" }),\n        `reference-${i}.png`\n      );\n    }\n\n    const baseURL = this.client.baseURL.replace(/\\/+$/, \"\");\n    const res = await fetch(`${baseURL}/images/edits`, {\n      method: \"POST\",\n      headers: {\n        Authorization: `Bearer ${this.client.apiKey}`,\n      },\n      body: formData,\n      signal: signal ?? null,\n    });\n\n    if (!res.ok) {\n      const body = await res.text().catch(() => \"\");\n      throw new Error(\n        `Image edit failed (${res.status}): ${body || res.statusText}`\n      );\n    }\n\n    const payload = await res.json();\n    const image = payload?.data?.[0];\n    if (image?.b64_json)\n      return { buffer: Buffer.from(image.b64_json, \"base64\") };\n    if (image?.url) {\n      const imgRes = await fetch(image.url, { signal: signal ?? null });\n      if (!imgRes.ok)\n        throw new Error(`Failed to fetch edited image: ${imgRes.status}`);\n      return { buffer: Buffer.from(await imgRes.arrayBuffer()) };\n    }\n    throw new Error(\"Image edit returned no image data.\");\n  }\n\n  async requestImage(prompt, size, signal) {","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/ImageGenerators/base.js#L79-L115","documentation":"Thrown by BaseImageGenerator.editImage after POSTing multipart/form-data to the OpenAI-compatible /images/edits endpoint. The check is !res.ok (any non-2xx HTTP status). It reads the response body as text (best-effort, falling back to empty string) and includes the numeric status plus the body or statusText so the underlying provider error is visible.","triggerScenarios":"Calling editImage when the provider rejects the edit request: 401/403 for bad or missing API key, 400 for unsupported model/size or malformed image input, 413 for oversized image upload, 429 for rate limit, 404 when the provider does not implement /images/edits, or 5xx for upstream failures.","commonSituations":"Using a model that does not support image edits against the /images/edits endpoint; passing a non-PNG reference image; API key for the image provider expired; hitting the image-generation rate limit; provider (e.g. some Ollama builds) does not implement the edits endpoint at all.","solutions":["Read the numeric status in the message: 401/403 → fix IMAGE_GEN_*_API_KEY; 400 → check model supports edits and image format; 429 → wait and retry; 404 → provider has no edits endpoint.","Confirm the selected IMAGE_GEN_MODEL_PREF actually supports image editing on the chosen provider.","Ensure reference images are PNG buffers and within the provider's size/upload limits.","Verify the base path env var points at a provider that implements /images/edits (OpenAI and Lemonade do; some Ollama builds do not)."],"exampleFix":"// before\nconst { buffer } = await generator.editImage({ prompt, images: [pngBuf] });\n\n// after: validate inputs and surface the status\nif (!pngBuf || pngBuf.length === 0) throw new Error('reference image is empty');\nlet result;\ntry {\n  result = await generator.editImage({ prompt, images: [pngBuf] });\n} catch (e) {\n  if (/\\(429\\)/.test(e.message)) throw new Error('rate limited — retry later');\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"function validateEditInputs(prompt, images) {\n  if (!prompt || typeof prompt !== 'string') throw new Error('editImage requires a non-empty prompt');\n  if (!Array.isArray(images) || images.length === 0) throw new Error('editImage requires at least one reference image Buffer');\n  if (!images.every(b => Buffer.isBuffer(b) && b.length > 0)) throw new Error('reference images must be non-empty Buffers');\n}","typeGuard":"/** @param {unknown} e */\nfunction isImageEditHttpError(e) {\n  return e instanceof Error && /^Image edit failed \\(\\d+\\):/.test(e.message);\n}","tryCatchPattern":"try {\n  return await generator.editImage({ prompt, images });\n} catch (e) {\n  const status = (e.message.match(/\\((\\d+)\\)/) || [,])[1];\n  if (status === '429') throw new Error('Rate limited by image provider — retry later');\n  if (status === '401' || status === '403') throw new Error('Bad image provider API key');\n  if (status === '404') throw new Error('Provider does not support /images/edits');\n  throw e;\n}","preventionTips":["Confirm the selected model supports image editing on the provider before calling editImage.","Pass PNG Buffers within the provider's size/upload limits.","Surface the embedded status code to route 429s to a retry and 401s to a key fix.","Verify the provider actually implements /images/edits (OpenAI/Lemonade do; some Ollama builds do not)."],"tags":["image-generation","image-edit","http-error","openai-compatible","network"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}