multica-ai/multica · error

create directory

Error message

create %s directory %s: %w

What it means

materialiseInCodexHome calls root.MkdirAll for the parent directories of the destination (e.g. the parent of a config file copy) inside the verified os.Root. Failure means the intermediate directory could not be created: a non-directory file exists in the way, permissions, or a symlink leaves the root (os.Root rejects links that escape the task home).

Solutions

  1. Inspect the offending intermediate path under the task home and remove the blocking file or escaping symlink
  2. Reset/recreate the task home if its contents are untrusted
  3. Check filesystem write permissions for the daemon user
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Join(codexHome, filepath.Dir(relPath))
if fi, err := os.Lstat(dir); err == nil && !fi.IsDir() {
	return fmt.Errorf("blocked path %s is not a directory", dir)
}

Prevention

When it happens

Trigger: A previous task left a regular file where a directory is needed; a symlinked intermediate directory points outside the task home; read-only filesystem.

Common situations: Reused task home polluted by earlier task output; a task linked an intermediate dir to /tmp or another task's area.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/28249530378304bf. Report an issue: GitHub.

Appendix: source

Thrown at server/internal/daemon/execenv/codex_home.go:1019

// daemon's mkdir, remove, or write outside it.
//
// This matters because a task home is reused: a prepare can run against a
// directory a previous task already wrote to. Without the root, a task that
// replaced an intermediate directory of its own home with a link to somewhere
// else would have the daemon delete and overwrite the link target on the next
// prepare. os.Root still allows links that stay inside the task home, which is
// harmless, and rejects the ones that leave it. The root itself is
// identity-checked by openVerifiedCodexHomeRoot.
func materialiseInCodexHome(codexHome, relPath, src, key string) error {
	root, err := openVerifiedCodexHomeRoot(codexHome, key)
	if err != nil {
		return err
	}
	defer root.Close()

	if dir := filepath.Dir(relPath); dir != "." {
		if err := root.MkdirAll(dir, 0o755); err != nil {
			return fmt.Errorf("create %s directory %s: %w", key, dir, err)
		}
	}
	if _, err := root.Lstat(relPath); err == nil {
		if err := root.Remove(relPath); err != nil {
			return fmt.Errorf("remove stale %s copy %s: %w", key, relPath, err)
		}
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("stat %s copy %s: %w", key, relPath, err)
	}

	in, err := os.Open(src)
	if err != nil {
		return fmt.Errorf("open %s %s: %w", key, src, err)
	}
	defer in.Close()

	out, err := root.OpenFile(relPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644)
	if err != nil {

View on GitHub (pinned to 2c0912b6ec)