{"record":{"id":"5e2bf97dcb6f9eaa","repo":"multica-ai/multica","slug":"upload-attachment-w","errorCode":null,"errorMessage":"upload attachment: %w","messagePattern":"upload attachment: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_attachment.go","lineNumber":91,"sourceCode":"\tif taskID == \"\" {\n\t\treturn fmt.Errorf(\"no chat task in context: run inside a chat task (MULTICA_TASK_ID set) or pass --task <id>\")\n\t}\n\n\tpath := args[0]\n\tif isHTTPURL(path) {\n\t\treturn fmt.Errorf(\"upload accepts a local file path, not a URL: %s\", path)\n\t}\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read file %s: %w\", path, err)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), cli.AtLeastAPITimeout(60*time.Second))\n\tdefer cancel()\n\n\tatt, err := client.UploadChatAttachment(ctx, data, path, taskID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"upload attachment: %w\", err)\n\t}\n\n\tfilename := filepath.Base(path)\n\t// Escape markdown label metacharacters in the filename so a name like\n\t// `report[v2].pdf` does not truncate the snippet's label. Files render as a\n\t// block-level attachment card via `!file[...]( )`; images render inline via\n\t// `![...]( )`.\n\tlabel := escapeMarkdownLabel(filename)\n\tmarkdown := fmt.Sprintf(\"!file[%s](%s)\", label, att.MarkdownURL)\n\tif strings.HasPrefix(att.ContentType, \"image/\") {\n\t\tmarkdown = fmt.Sprintf(\"![%s](%s)\", label, att.MarkdownURL)\n\t}\n\tfmt.Fprintln(os.Stderr, \"Uploaded:\", filename)\n\n\treturn cli.PrintJSON(os.Stdout, map[string]any{\n\t\t\"id\":           att.ID,\n\t\t\"filename\":     filename,\n\t\t\"markdown_url\": att.MarkdownURL,","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_attachment.go#L73-L109","documentation":"After reading the file locally, the command calls client.UploadChatAttachment to POST it to the server under a 60s timeout. This error wraps any API-side failure: transport errors, non-2xx responses, auth rejection, or server-side upload limits.","triggerScenarios":"Expired or invalid auth token; server unreachable; file exceeds the server's maximum attachment size; task id rejected by the server (deleted task, other workspace); timeout on slow links with large files.","commonSituations":"Token saved for an old/dead workspace; large binary files (videos, dumps) tripping size limits; self-hosted server behind a proxy with a low client_max_body_size; flaky network from an agent sandbox.","solutions":["Check auth and connectivity first: `multica auth status`","Confirm the task id is valid and in the current workspace: `multica task list`","Retry once for transient network errors; check server logs if it persists","Reduce file size or compress before upload if the server rejects it as too large","On self-hosted deployments behind nginx/traefik, raise the request body limit"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"# bash: distinguish transient from permanent\nif ! multica attachment upload \"$f\" --task \"$tid\" 2>err.txt; then\n  grep -qiE 'timeout|connection|reset|EOF' err.txt && retry=1 || retry=0\n  [ \"$retry\" = 1 ] && { sleep 3; multica attachment upload \"$f\" --task \"$tid\"; } || cat err.txt\nfi","preventionTips":["Run `multica auth status` before scripted upload batches","Keep files under the server's attachment size limit; compress large binaries first","Retry once on transient network failures — API uploads are idempotent per call"],"tags":["cli","attachment","network","api","upload"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}