{"record":{"id":"fe02dea5abf709fc","repo":"multica-ai/multica","slug":"read-file-w","errorCode":null,"errorMessage":"read file: %w","messagePattern":"read file: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_agent.go","lineNumber":936,"sourceCode":"\t\treturn fmt.Errorf(\"file not found: %w\", err)\n\t}\n\n\t// Validate extension.\n\text := strings.ToLower(filepath.Ext(filePath))\n\tvalidExts := map[string]bool{\".png\": true, \".jpg\": true, \".jpeg\": true, \".gif\": true, \".webp\": true}\n\tif !validExts[ext] {\n\t\treturn fmt.Errorf(\"unsupported file format %q: must be .png, .jpg, .jpeg, .gif, or .webp\", ext)\n\t}\n\n\t// Client-side size guard: reject files > 5MB.\n\tconst maxSize = 5 << 20 // 5 MB\n\tif info.Size() > maxSize {\n\t\treturn fmt.Errorf(\"file too large: %d bytes (max 5MB)\", info.Size())\n\t}\n\n\tfileData, err := os.ReadFile(filePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read file: %w\", err)\n\t}\n\n\t// Defensive re-check: guard against TOCTOU race where the file\n\t// was swapped between stat and read.\n\tif len(fileData) > maxSize {\n\t\treturn fmt.Errorf(\"file too large: %d bytes (max 5MB)\", len(fileData))\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), cli.AtLeastAPITimeout(60*time.Second))\n\tdefer cancel()\n\n\t// Agent existence pre-check.\n\tvar agent map[string]any\n\tif err := client.GetJSON(ctx, \"/api/agents/\"+args[0], &agent); err != nil {\n\t\treturn fmt.Errorf(\"get agent: %w\", err)\n\t}\n\n\tid, url, err := client.UploadFileWithURL(ctx, fileData, filePath)","sourceCodeStart":918,"sourceCodeEnd":954,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_agent.go#L918-L954","documentation":"Wrapped error from os.ReadFile when the avatar file passed the earlier existence/extension/size checks but could not be read into memory — deleted or truncated between stat and read, or read permission revoked. The %w is a *fs.PathError with the OS cause.","triggerScenarios":"The file is removed, truncated, or chmod'd to 000 in the window between os.Stat and os.ReadFile inside runAgentAvatar; more commonly, read permission is missing even though directory listing made Stat succeed.","commonSituations":"Temporary files being garbage-collected mid-command, editors swapping files on save, files on network mounts that vanish, or ownership mismatches (file owned by another user, mode 640).","solutions":["Check permissions: `ls -l <file>` and `chmod u+r <file>` if missing read access","If the file is transient, copy it to a stable local path first (`cp /tmp/x.png ./avatar.png`) and retry","Verify the file still exists and is non-empty right before the command in scripts","Run as a user with read access to the file (or chown it)"],"exampleFix":"# before\nmultica agent avatar agt_1 --file /mnt/share/av.png\n# Error: read file: open /mnt/share/av.png: permission denied\n\n# after\ncp /mnt/share/av.png ./av.png && chmod u+r ./av.png\nmultica agent avatar agt_1 --file ./av.png","handlingStrategy":"validation","validationCode":"[ -r \"$AVATAR_FILE\" ] || { echo \"cannot read $AVATAR_FILE\"; exit 1; }\nmultica agent avatar \"$AGENT_ID\" --file \"$AVATAR_FILE\"","typeGuard":null,"tryCatchPattern":"fileData, err := os.ReadFile(filePath)\nif err != nil {\n\treturn fmt.Errorf(\"read file: %w\", err)\n}","preventionTips":["Use [ -r ] to assert readability, not just existence","Copy transient/network files to stable local storage before upload","Avoid uploading files that other processes are still writing"],"tags":["cli","filesystem","permissions","avatar"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}