fatedier/frp · error
failed to create temp file: %w
Error message
failed to create temp file: %w
What it means
os.OpenFile on Path + ".tmp" (O_WRONLY|O_CREATE|O_TRUNC, mode 0600) failed, so the atomic-write sequence could not even start. Everything after this (write, fsync, rename) is skipped; the in-memory change that triggered the save has already been applied and will be rolled back by persistOrRollbackUnlocked.
Source
Thrown at pkg/config/source/store.go:152
for _, v := range s.visitors {
stored.Visitors = append(stored.Visitors, v1.TypedVisitorConfig{VisitorConfigurer: v})
}
data, err := jsonx.MarshalIndent(stored, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal JSON: %w", err)
}
dir := filepath.Dir(s.config.Path)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
tmpPath := s.config.Path + ".tmp"
f, err := os.OpenFile(tmpPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("failed to create temp file: %w", err)
}
if _, err := f.Write(data); err != nil {
f.Close()
os.Remove(tmpPath)
return fmt.Errorf("failed to write temp file: %w", err)
}
if err := f.Sync(); err != nil {
f.Close()
os.Remove(tmpPath)
return fmt.Errorf("failed to sync temp file: %w", err)
}
if err := f.Close(); err != nil {
os.Remove(tmpPath)
return fmt.Errorf("failed to close temp file: %w", err)
}View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Confirm write permission on the directory: touch <dir>/.wtest as the running user
- If a DIRECTORY named <Path>.tmp exists, remove or rename it
- For read-only mounts, remount rw or relocate Path to a writable volume
- Check audit logs (ausearch -m avc / dmesg) for SELinux/AppArmor denials if permissions look fine
Example fix
# before: .tmp path occupied by a directory ls -la /var/lib/frpc/ # store.json.tmp/ <- directory, OpenFile fails # after rm -rf /var/lib/frpc/store.json.tmp
Defensive patterns
Strategy: validation
Validate before calling
func canCreateTempFile(path string) error {
tmp := path + ".tmp"
if fi, err := os.Stat(tmp); err == nil && fi.IsDir() {
return fmt.Errorf("%s exists and is a directory", tmp)
}
f, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("cannot write %s: %w", tmp, err)
}
f.Close()
os.Remove(tmp)
return nil
} Prevention
- Check at startup that the process can write the store directory (probe-create a file)
- Avoid read-only mounts for the store path; use emptyDir/PVC in k8s
- Clean up stray *.tmp artifacts in the store directory during deploy
When it happens
Trigger: Directory not writable for the process user; read-only filesystem mount; an existing directory named exactly <Path>.tmp blocks file creation; SELinux/AppArmor denial; path length over NAME_MAX because of the .tmp suffix.
Common situations: Container with a read-only or root-owned volume mounted at the store directory; a leftover <store>.tmp directory from an earlier interrupted run or backup tool; security policy blocking writes outside allowed labels.
Related errors
- failed to load existing data: %w
- failed to create directory: %w
- failed to write temp file: %w
- failed to sync temp file: %w
- failed to close temp file: %w
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/586155fa2f916684.
Report an issue: GitHub.