paperclipai/paperclip · warning · Error

Attachment was removed

Error message

Attachment was removed

What it means

In TaskChatComposer's `uploadInlineImage`, after the async upload resolves it re-checks that the placeholder attachment (tracked by `id`) still exists in `attachmentsRef.current`. If the user removed the attachment while the upload was in flight, the composer throws instead of mutating state for a deleted item.

Solutions

  1. Expected and harmless: catch it in the caller and ignore (attachment intentionally removed) — ensure the catch is silent for this case.
  2. UX fix: disable the per-attachment remove button while `item.uploading` is true.
  3. Alternative: re-add nothing but return early instead of throwing when the id is absent.

Example fix

// before
if (!attachmentsRef.current.some((item) => item.id === id))
  throw new Error("Attachment was removed");
// after
if (!attachmentsRef.current.some((item) => item.id === id))
  return; // user removed it mid-upload; nothing to update
Defensive patterns

Strategy: try-catch

Validate before calling

if (!attachmentsRef.current.some((i) => i.id === id)) return; // still attached?

Type guard

const stillAttached = (id: string) => attachmentsRef.current.some((item) => item.id === id);

Try / catch

try { await uploadInlineImage(file); } catch (e) { if (!/Attachment was removed/.test(e.message)) showToast('Upload failed'); }

Prevention

When it happens

Trigger: Start an inline image upload, then click remove on that attachment before the upload completes; the resolved upload then finds the id gone from `attachmentsRef.current`.

Common situations: Slow uploads on poor networks combined with quick user edits; user hits a 'remove all attachments' action mid-upload; rapid delete/undo interactions.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/287eb6fcd8e12fe1. Report an issue: GitHub.

Appendix: source

Thrown at ui/src/components/task-chat/TaskChatComposer.tsx:685

    const id = crypto.randomUUID();
    setAttachments((prev) => [
      ...prev,
      {
        id,
        name: file.name,
        size: file.size,
        inline: true,
        status: "uploading",
      },
    ]);
    try {
      const attachment = onAttachImage ? await onAttachImage(file) : undefined;
      const url = onAttachImage
        ? attachment?.contentPath
        : await onImageUpload?.(file);
      if (!url) throw new Error("Upload did not return a file URL");
      if (!attachmentsRef.current.some((item) => item.id === id))
        throw new Error("Attachment was removed");
      setAttachments((prev) =>
        prev.map((item) =>
          item.id === id
            ? {
                ...item,
                attachmentId: attachment?.id,
                contentPath: url,
                status: "attached",
              }
            : item,
        ),
      );
      return url;
    } catch (err) {
      setAttachments((prev) =>
        prev.map((item) =>
          item.id === id
            ? {

View on GitHub (pinned to 3f1d897a7c)