{"record":{"id":"fffcaacec25e1e99","repo":"larksuite/cli","slug":"cannot-write-file-w","errorCode":null,"errorMessage":"cannot write file: %w","messagePattern":"cannot write file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/response.go","lineNumber":222,"sourceCode":"// ── File saving ──\n\n// SaveResponse writes an API response body to the given outputPath and returns metadata.\n// It delegates to FileIO.Save for path validation and atomic write; fio must not be nil.\nfunc SaveResponse(fio fileio.FileIO, resp *larkcore.ApiResp, outputPath string) (map[string]interface{}, error) {\n\tresult, err := fio.Save(outputPath, fileio.SaveOptions{\n\t\tContentType:   resp.Header.Get(\"Content-Type\"),\n\t\tContentLength: int64(len(resp.RawBody)),\n\t}, bytes.NewReader(resp.RawBody))\n\tif err != nil {\n\t\tvar me *fileio.MkdirError\n\t\tvar we *fileio.WriteError\n\t\tswitch {\n\t\tcase errors.Is(err, fileio.ErrPathValidation):\n\t\t\treturn nil, fmt.Errorf(\"unsafe output path: %w\", err)\n\t\tcase errors.As(err, &me):\n\t\t\treturn nil, fmt.Errorf(\"create directory: %w\", err)\n\t\tcase errors.As(err, &we):\n\t\t\treturn nil, fmt.Errorf(\"cannot write file: %w\", err)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"cannot write file: %w\", err)\n\t\t}\n\t}\n\n\tresolvedPath, err := fio.ResolvePath(outputPath)\n\tif err != nil || resolvedPath == \"\" {\n\t\tresolvedPath = outputPath\n\t}\n\treturn map[string]interface{}{\n\t\t\"saved_path\":   resolvedPath,\n\t\t\"size_bytes\":   result.Size(),\n\t\t\"content_type\": resp.Header.Get(\"Content-Type\"),\n\t}, nil\n}\n\n// ResolveFilename picks a filename from the response headers.\n// Priority: Content-Disposition filename > Content-Type extension > \"download.bin\".","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/client/response.go#L204-L240","documentation":"SaveResponse wraps failures from the FileIO WriteFile call as 'cannot write file: %w' when the error is a typed fileio.WriteError. This means the directory was created (or existed) but writing the response body to outputPath failed. It is the file-write counterpart to 'create directory' and 'unsafe output path'.","triggerScenarios":"Calling SaveResponse with an outputPath where WriteFile fails: disk full, permission denied on the target file, target path is a directory, or the storage backend rejects the write after mkdir succeeded.","commonSituations":"Read-only target directories, quota/disk-full conditions, antivirus or sync tools locking the file, saving onto a mounted volume that went read-only, or a FileIO backend write limit.","solutions":["Check free disk space and write permissions for the target file's directory","Verify outputPath is not an existing directory","Write to a writable location (temp dir or FileIO-allowed tree via runtime.ResolveSavePath)","Read the wrapped cause for the exact OS error and fix accordingly"],"exampleFix":"// before\nclient.SaveResponse(resp, \"/mnt/readonly/response.json\")\n// after\nclient.SaveResponse(resp, filepath.Join(os.TempDir(), \"response.json\"))","handlingStrategy":"try-catch","validationCode":"if st, err := os.Stat(outputPath); err == nil && st.IsDir() {\n    return fmt.Errorf(\"%s is a directory\", outputPath)\n}","typeGuard":"var we *fileio.WriteError\nif errors.As(err, &we) { /* handle write failure specifically */ }","tryCatchPattern":"_, err := client.SaveResponse(resp, outputPath)\nif err != nil {\n    var we *fileio.WriteError\n    if errors.As(err, &we) {\n        // inspect we's cause: disk full / permission / is-a-directory\n    }\n    return err\n}","preventionTips":["Ensure the target directory is writable and has free disk space","Confirm outputPath is a file path, not an existing directory","Avoid saving to read-only mounts or synced/locked locations","Use runtime.ResolveSavePath to land on a valid writable path"],"tags":["filesystem","write","io"],"backgroundTag":"file-write-failed","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}