{"record":{"id":"882336a8be0d4958","repo":"paperclipai/paperclip","slug":"upload-did-not-return-a-file-url","errorCode":null,"errorMessage":"Upload did not return a file URL","messagePattern":"Upload did not return a file URL","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/src/components/task-chat/TaskChatComposer.tsx","lineNumber":683,"sourceCode":"  /** Upload an image and return its URL for inline `![](src)` markdown. */\n  async function uploadInlineImage(file: File): Promise<string> {\n    const id = crypto.randomUUID();\n    setAttachments((prev) => [\n      ...prev,\n      {\n        id,\n        name: file.name,\n        size: file.size,\n        inline: true,\n        status: \"uploading\",\n      },\n    ]);\n    try {\n      const attachment = onAttachImage ? await onAttachImage(file) : undefined;\n      const url = onAttachImage\n        ? attachment?.contentPath\n        : await onImageUpload?.(file);\n      if (!url) throw new Error(\"Upload did not return a file URL\");\n      if (!attachmentsRef.current.some((item) => item.id === id))\n        throw new Error(\"Attachment was removed\");\n      setAttachments((prev) =>\n        prev.map((item) =>\n          item.id === id\n            ? {\n                ...item,\n                attachmentId: attachment?.id,\n                contentPath: url,\n                status: \"attached\",\n              }\n            : item,\n        ),\n      );\n      return url;\n    } catch (err) {\n      setAttachments((prev) =>\n        prev.map((item) =>","sourceCodeStart":665,"sourceCodeEnd":701,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/ui/src/components/task-chat/TaskChatComposer.tsx#L665-L701","documentation":"Post-condition guard in TaskChatComposer's uploadInlineImage: after requesting an upload via onAttachImage (or onImageUpload), the returned attachment's contentPath/URL is undefined, so the composer cannot build the inline `![](src)` markdown and aborts the (already-inserted 'uploading') attachment instead of embedding a broken image reference. It fires when the upload handler resolves without a file URL — a misconfigured or failed upload callback — not a network error itself.","triggerScenarios":"Thrown at ui/src/components/task-chat/TaskChatComposer.tsx:211 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Retry the upload; if it persists, check the asset upload endpoint response for why no file URL was returned."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}