fatedier/frp · error

failed to create directory: %w

Error message

failed to create directory: %w

What it means

saveToFileUnlocked failed to create the parent directory of the store path via os.MkdirAll before writing the temp file. The library expects to be able to create every missing directory component of filepath.Dir(Path).

Source

Thrown at pkg/config/source/store.go:145

		Proxies:  make([]v1.TypedProxyConfig, 0, len(s.proxies)),
		Visitors: make([]v1.TypedVisitorConfig, 0, len(s.visitors)),
	}

	for _, p := range s.proxies {
		stored.Proxies = append(stored.Proxies, v1.TypedProxyConfig{ProxyConfigurer: p})
	}
	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)

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Check the directory chain: namei -l <path> shows permissions per component and where it fails
  2. Pre-create the directory with correct ownership: mkdir -p <dir> && chown <user> <dir>
  3. Remove/rename any regular file that occupies a needed directory component
  4. Move the store to a writable location (e.g. $HOME/.frp/store.json or an emptyDir in k8s) if the FS is read-only

Example fix

# before
Path: /var/lib/frpc/store.json   # /var/lib/frpc missing, process non-root

# after
sudo mkdir -p /var/lib/frpc && sudo chown $USER /var/lib/frpc
# or use a writable path
Path: /home/user/.frp/store.json
Defensive patterns

Strategy: validation

Validate before calling

func ensureStoreDir(path string) error {
	dir := filepath.Dir(path)
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return fmt.Errorf("cannot create store dir %s: %w", dir, err)
	}
	if err := unix.Access(dir, unix.W_OK); err != nil { // or os.WriteFile probe
		return fmt.Errorf("no write access to %s", dir)
	}
	return nil
}

Prevention

When it happens

Trigger: Path like /var/lib/frpc/store.json where /var/lib/frpc (or any parent) cannot be created because of EACCES/EPERM; a parent component already exists as a regular FILE (MkdirAll then fails with ENOTDIR); read-only root filesystem in a container.

Common situations: Running in a minimal container where /var/lib is root-owned and the process runs non-root; typo like Path=/var/lib/frpc.json/dir/store.json where a file occupies an intermediate name; Docker with read-only volumes.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/b987e40ba612cc61. Report an issue: GitHub.