ipfs/kubo · error

cannot write to %s, incorrect permissions

Error message

cannot write to %s, incorrect permissions

What it means

Thrown by checkWritable when stat-ing the repo dir itself fails with a permission error (the dir's parent is inaccessible to the current user). Kubo tells you the directory cannot be written due to permissions. Note a formatting bug in the source: the message interpolates the error value `err` where the directory path was intended, so the %s shows the underlying error text rather than the path.

Source

Thrown at cmd/ipfs/kubo/init.go:200

		testfile := filepath.Join(dir, "test")
		fi, err := os.Create(testfile)
		if err != nil {
			if os.IsPermission(err) {
				return fmt.Errorf("%s is not writeable by the current user", dir)
			}
			return fmt.Errorf("unexpected error while checking writeablility of repo root: %s", err)
		}
		fi.Close()
		return os.Remove(testfile)
	}

	if os.IsNotExist(err) {
		// dir doesn't exist, check that we can create it
		return os.Mkdir(dir, 0o775)
	}

	if os.IsPermission(err) {
		return fmt.Errorf("cannot write to %s, incorrect permissions", err)
	}

	return err
}

func addDefaultAssets(out io.Writer, repoRoot string) error {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
		return err
	}

	nd, err := core.NewNode(ctx, &core.BuildCfg{Repo: r})
	if err != nil {
		return err
	}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Add execute (traverse) permission on every ancestor of the path: `chmod +x <parent-dirs>` along IPFS_PATH.
  2. Move IPFS_PATH to a location with traversable parents, e.g. `export IPFS_PATH=$(mktemp -d)`.
  3. Ignore the misleading text after 'cannot write to' (it contains the OS error, not the path): the path is whatever IPFS_PATH or the init argument was; re-check it with `ls -ld`.

Example fix

// before
chmod 600 /home/user/data   # blocks traversal, init fails
// after
chmod 755 /home/user/data   # or move IPFS_PATH elsewhere
Defensive patterns

Strategy: validation

Validate before calling

dir := os.Getenv("IPFS_PATH")
if dir == "" {
	dir = "~/.ipfs"
}
if _, err := os.Stat(dir); os.IsPermission(err) {
	log.Fatalf("cannot traverse to %s: %v — check +x on all ancestors", dir, err)
}
for p := filepath.Dir(dir); p != "/"; p = filepath.Dir(p) {
	if fi, err := os.Stat(p); err == nil && fi.Mode().Perm()&0o100 == 0 {
		log.Fatalf("ancestor %s blocks traversal (missing x bit)", p)
	}
}

Prevention

When it happens

Trigger: IPFS_PATH (or target dir) exists per the caller but os.Stat returns a permission error — typically a non-executable (no x bit) ancestor directory blocking traversal, e.g. ~/private/parent with mode 0600, so stat of the dir itself gets EACCES.

Common situations: IPFS_PATH placed inside another user's home or a locked-down directory whose parents deny +x; a hardened permissions setup accidentally removing execute bits from a path component; container setups with restrictive volume modes.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/2be949d3661f6d47. Report an issue: GitHub.