multica-ai/multica · error

resolve home directory: %w (set MULTICA_WORKSPACES_ROOT to o

Error message

resolve home directory: %w (set MULTICA_WORKSPACES_ROOT to override)

What it means

ResolveWorkspacesRoot needs $HOME to build the default workspaces directory ($HOME/multica_workspaces[_<profile>]) and os.UserHomeDir() failed — on Unix this means $HOME is empty; on Windows it means the user profile APIs failed. The message suggests the supported escape hatch: set MULTICA_WORKSPACES_ROOT (or pass the override) to skip home resolution entirely.

Source

Thrown at server/internal/daemon/config.go:621

// would otherwise scan the default root and silently report the wrong tree.
const TaskWorkspacesRootEnv = "MULTICA_TASK_WORKSPACES_ROOT"

// ResolveWorkspacesRoot returns the absolute path that the daemon and CLI
// should treat as the workspaces root. Resolution order: explicit override >
// MULTICA_WORKSPACES_ROOT env > default ($HOME/multica_workspaces, or
// $HOME/multica_workspaces_<profile> for a named profile). Read-only callers
// (e.g. `multica daemon disk-usage`) use this directly so they pick the same
// directory the running daemon would have picked. Inside a managed task use
// TaskWorkspacesRootEnv instead — see resolveDiskUsageRoot.
func ResolveWorkspacesRoot(profile, override string) (string, error) {
	root := strings.TrimSpace(os.Getenv("MULTICA_WORKSPACES_ROOT"))
	if override != "" {
		root = override
	}
	if root == "" {
		home, err := os.UserHomeDir()
		if err != nil {
			return "", fmt.Errorf("resolve home directory: %w (set MULTICA_WORKSPACES_ROOT to override)", err)
		}
		if profile != "" {
			root = filepath.Join(home, "multica_workspaces_"+profile)
		} else {
			root = filepath.Join(home, "multica_workspaces")
		}
	}
	abs, err := filepath.Abs(root)
	if err != nil {
		return "", fmt.Errorf("resolve absolute workspaces root: %w", err)
	}
	return abs, nil
}

// ArtifactPatternsFromEnv returns the configured artifact patternSet — the
// same list the GC loop consults when it runs the artifact-only cleanup. The
// disk-usage CLI uses this to make sure the "artifact size" it reports
// matches what the GC would actually reclaim.

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Set MULTICA_WORKSPACES_ROOT=/var/lib/multica/workspaces (or any absolute path) for the daemon's environment
  2. Alternatively set HOME explicitly (systemd Environment=, Docker ENV, or -e HOME=...)
  3. For disk-usage, pass the root override directly so no environment is consulted

Example fix

# before (systemd unit with no HOME)
[Service]
ExecStart=/usr/local/bin/multica daemon

# after
[Service]
Environment="MULTICA_WORKSPACES_ROOT=/var/lib/multica/workspaces"
ExecStart=/usr/local/bin/multica daemon
Defensive patterns

Strategy: validation

Validate before calling

// Guarantee a root exists before the daemon starts.
func ensureWorkspacesRoot() error {
    if strings.TrimSpace(os.Getenv("MULTICA_WORKSPACES_ROOT")) == "" {
        home, err := os.UserHomeDir()
        if err != nil {
            return fmt.Errorf("no MULTICA_WORKSPACES_ROOT and no HOME: set MULTICA_WORKSPACES_ROOT")
        }
        _ = home // would build default under home
    }
    return nil
}

Try / catch

Catch at startup; on this message, set MULTICA_WORKSPACES_ROOT to an absolute path in the service environment and restart — do not retry, the environment will not fix itself.

Prevention

When it happens

Trigger: Running the daemon or 'multica daemon disk-usage' as a service/container/systemd unit whose environment has no HOME set, or with HOME deliberately cleared. Only hit when neither MULTICA_WORKSPACES_ROOT nor an override argument is provided.

Common situations: Docker containers running as root without HOME, systemd services without Environment="HOME=...", cron jobs, and CI runners with minimal env.

Related errors


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