{"record":{"id":"4d4fc370ceaf0090","repo":"charmbracelet/crush","slug":"error-writing-file-w","errorCode":null,"errorMessage":"error writing file: %w","messagePattern":"error writing file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/write.go","lineNumber":139,"sourceCode":"\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.ToolResponse{}, err\n\t\t\t}\n\t\t\tif !p {\n\t\t\t\tresp := NewPermissionDeniedResponse()\n\t\t\t\tresp = fantasy.WithResponseMetadata(resp, WriteResponseMetadata{\n\t\t\t\t\tDiff:      diff,\n\t\t\t\t\tAdditions: additions,\n\t\t\t\t\tRemovals:  removals,\n\t\t\t\t})\n\t\t\t\treturn resp, nil\n\t\t\t}\n\n\t\t\terr = os.WriteFile(filePath, []byte(params.Content), 0o644)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"error writing file: %w\", err)\n\t\t\t}\n\n\t\t\t// Check if file exists in history\n\t\t\tfile, err := files.GetByPathAndSession(ctx, filePath, sessionID)\n\t\t\tif err != nil {\n\t\t\t\t_, err = files.Create(ctx, sessionID, filePath, oldContent)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// Log error but don't fail the operation\n\t\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"error creating file history: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif file.Content != oldContent {\n\t\t\t\t// User manually changed the content; store an intermediate version\n\t\t\t\t_, err = files.CreateVersion(ctx, sessionID, filePath, oldContent)\n\t\t\t\tif err != nil {\n\t\t\t\t\tslog.Error(\"Error creating file history version\", \"error\", err)\n\t\t\t\t}\n\t\t\t}","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/write.go#L121-L157","documentation":"The final os.WriteFile(filePath, content, 0o644) failed, so the target file was not written. This is the core write step of the tool; any OS-level write error (permissions, no space, target is a directory, file locked by immutable attribute) surfaces here wrapped.","triggerScenarios":"filePath exists as a directory (IsDir case slipped through), the file is read-only or owned by another user (EACCES), disk is full (ENOSPC), or an immutable flag (chattr +i) is set.","commonSituations":"Agent tries to overwrite a protected file (e.g. ~/.ssh, system configs) without permission; writing to a path that is actually a directory; ENOSPC on CI runners with small disks; root-owned files in repos checked out with restrictive modes.","solutions":["Check the target is not a directory and is writable by the process user (ls -la).","Fix permissions/ownership (chmod/chown) or run the agent as a user with access.","Free disk space if ENOSPC.","Remove immutable attributes if set (chattr -i)."],"exampleFix":"// before\n{\"file_path\": \"build/output\", \"content\": \"...\"}  // build/output is a directory\n\n// after\n{\"file_path\": \"build/output/result.txt\", \"content\": \"...\"}","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(targetPath); err == nil && info.IsDir() {\n    return fmt.Errorf(\"%s is a directory, not a file\", targetPath)\n}\nif info, err := os.Stat(targetPath); err == nil {\n    f, oerr := os.OpenFile(targetPath, os.O_WRONLY, 0)\n    if oerr != nil {\n        return fmt.Errorf(\"%s is not writable by this user\", targetPath)\n    }\n    f.Close()\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, fs.ErrPermission) { /* fix chmod/chown */ }\nif errors.Is(err, syscall.ENOSPC) { /* free disk space */ }\nif errors.Is(err, syscall.EISDIR) { /* target is a directory */ }","preventionTips":["Never target directories, ~/.ssh, or system config paths with the write tool.","Run the agent under a user with write access to the repo.","Keep CI disk usage monitored to avoid ENOSPC."],"tags":["go","filesystem","write-file","permissions"],"backgroundTag":"file-write-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}