larksuite/cli · error
create temp file: %w
Error message
create temp file: %w
What it means
ExclusiveWriteFromReader writes content to a temp file in the target's directory and then links it into place without ever replacing an existing target. This error wraps the failure of vfs.CreateTemp when creating that staging temp file ('.'+base+'.*.tmp' in the target directory). The write never starts; the original target is untouched.
Source
Thrown at internal/vfs/localfileio/atomicwrite.go:60
// Link, which combines both guarantees this call has to make:
//
// - No-clobber. Link fails with EEXIST instead of replacing an existing
// target, so the refusal is decided by the commit itself. A preceding
// existence check cannot do this: another writer may create the file while
// this one is still copying.
// - Whole-file visibility. The target name appears only once the content is
// complete and synced. Writing directly to the final name with O_EXCL would
// satisfy no-clobber but publish a partial file for the duration of the
// copy, and a killed process would leave that partial file behind as a
// phantom target for the next attempt.
//
// Rename cannot serve as the commit step because it replaces an existing target
// unconditionally.
func ExclusiveWriteFromReader(path string, reader io.Reader, perm os.FileMode) (int64, error) {
dir := filepath.Dir(path)
tmp, err := vfs.CreateTemp(dir, "."+filepath.Base(path)+".*.tmp")
if err != nil {
return 0, fmt.Errorf("create temp file: %w", err)
}
tmpName := tmp.Name()
closed := false
defer func() {
if !closed {
tmp.Close()
}
// The temp name is removed either way: on failure it is the partial
// artifact, on success the link has already published the content.
vfs.Remove(tmpName)
}()
if err := tmp.Chmod(perm); err != nil {
return 0, err
}
copied, err := io.Copy(tmp, reader)
if err != nil {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Create the parent directory first (e.g. os.MkdirAll(filepath.Dir(path), 0o755) or the vfs equivalent)
- Check that the process has write permission on the target directory
- Verify the target path is correct and on a mounted, writable filesystem
- Inspect the wrapped cause (%w) — e.g. ENOENT vs EACCES — to distinguish missing dir from permissions
Example fix
// before
n, err := ExclusiveWriteFromReader("/cfg/app/missing/file.json", r, 0o600)
// after
if err := os.MkdirAll("/cfg/app/missing", 0o755); err != nil {
return err
}
n, err := ExclusiveWriteFromReader("/cfg/app/missing/file.json", r, 0o600) Defensive patterns
Strategy: validation
Validate before calling
func ensureWritableDir(path string) error {
dir := filepath.Dir(path)
fi, err := os.Stat(dir)
if err != nil { return fmt.Errorf("target dir missing: %w", err) }
if !fi.IsDir() { return fmt.Errorf("%s is not a directory", dir) }
if err := syscall.Access(dir, syscall.O_RDWR); err != nil { return fmt.Errorf("dir not writable: %w", err) }
return nil
}
// call before ExclusiveWriteFromReader / SaveExclusive Type guard
func canStage(path string) bool {
dir := filepath.Dir(path)
fi, err := os.Stat(dir)
return err == nil && fi.IsDir()
} Try / catch
if _, err := ExclusiveWriteFromReader(path, r, 0o600); err != nil && strings.Contains(err.Error(), "create temp file") {
if mkErr := os.MkdirAll(filepath.Dir(path), 0o755); mkErr != nil { return mkErr }
// retry once after creating the directory
} Prevention
- Create parent directories before exclusive writes
- Verify write permissions on config/workspace directories at startup
- Check the wrapped errno: ENOENT = missing dir, EACCES = permissions, ENOSPC = disk full
- Keep target paths within managed directories the CLI owns
When it happens
Trigger: The target's parent directory does not exist, is not writable, or the path is invalid, causing CreateTemp to fail — raised via ExclusiveWriteFromReader (called by SaveExclusive and tests).
Common situations: Saving to a directory that was deleted or never created; read-only workspace/config directory; permission-changed directory; path pointing at a nonexistent mount; disk-full edge at creation.
Related errors
- open lock file: %w
- invalid chart size: {size!r}
- %s: cannot stat %q: %w
- %s: path %q is world-readable (mode %04o)
- %s: path %q is group-readable (mode %04o)
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/a953389db1883d8d.
Report an issue: GitHub.