larksuite/cli · error

cannot write file: %w

Error message

cannot write file: %w

What it means

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'.

Source

Thrown at internal/client/response.go:222

// ── File saving ──

// SaveResponse writes an API response body to the given outputPath and returns metadata.
// It delegates to FileIO.Save for path validation and atomic write; fio must not be nil.
func SaveResponse(fio fileio.FileIO, resp *larkcore.ApiResp, outputPath string) (map[string]interface{}, error) {
	result, err := fio.Save(outputPath, fileio.SaveOptions{
		ContentType:   resp.Header.Get("Content-Type"),
		ContentLength: int64(len(resp.RawBody)),
	}, bytes.NewReader(resp.RawBody))
	if err != nil {
		var me *fileio.MkdirError
		var we *fileio.WriteError
		switch {
		case errors.Is(err, fileio.ErrPathValidation):
			return nil, fmt.Errorf("unsafe output path: %w", err)
		case errors.As(err, &me):
			return nil, fmt.Errorf("create directory: %w", err)
		case errors.As(err, &we):
			return nil, fmt.Errorf("cannot write file: %w", err)
		default:
			return nil, fmt.Errorf("cannot write file: %w", err)
		}
	}

	resolvedPath, err := fio.ResolvePath(outputPath)
	if err != nil || resolvedPath == "" {
		resolvedPath = outputPath
	}
	return map[string]interface{}{
		"saved_path":   resolvedPath,
		"size_bytes":   result.Size(),
		"content_type": resp.Header.Get("Content-Type"),
	}, nil
}

// ResolveFilename picks a filename from the response headers.
// Priority: Content-Disposition filename > Content-Type extension > "download.bin".

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check free disk space and write permissions for the target file's directory
  2. Verify outputPath is not an existing directory
  3. Write to a writable location (temp dir or FileIO-allowed tree via runtime.ResolveSavePath)
  4. Read the wrapped cause for the exact OS error and fix accordingly

Example fix

// before
client.SaveResponse(resp, "/mnt/readonly/response.json")
// after
client.SaveResponse(resp, filepath.Join(os.TempDir(), "response.json"))
Defensive patterns

Strategy: try-catch

Validate before calling

if st, err := os.Stat(outputPath); err == nil && st.IsDir() {
    return fmt.Errorf("%s is a directory", outputPath)
}

Type guard

var we *fileio.WriteError
if errors.As(err, &we) { /* handle write failure specifically */ }

Try / catch

_, err := client.SaveResponse(resp, outputPath)
if err != nil {
    var we *fileio.WriteError
    if errors.As(err, &we) {
        // inspect we's cause: disk full / permission / is-a-directory
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/fffcaacec25e1e99. Report an issue: GitHub.