{"record":{"id":"66e0f40c96eb43e5","repo":"multica-ai/multica","slug":"resolve-home-directory-w-set-multica-workspaces","errorCode":null,"errorMessage":"resolve home directory: %w (set MULTICA_WORKSPACES_ROOT to override)","messagePattern":"resolve home directory: %w \\(set MULTICA_WORKSPACES_ROOT to override\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/config.go","lineNumber":621,"sourceCode":"// would otherwise scan the default root and silently report the wrong tree.\nconst TaskWorkspacesRootEnv = \"MULTICA_TASK_WORKSPACES_ROOT\"\n\n// ResolveWorkspacesRoot returns the absolute path that the daemon and CLI\n// should treat as the workspaces root. Resolution order: explicit override >\n// MULTICA_WORKSPACES_ROOT env > default ($HOME/multica_workspaces, or\n// $HOME/multica_workspaces_<profile> for a named profile). Read-only callers\n// (e.g. `multica daemon disk-usage`) use this directly so they pick the same\n// directory the running daemon would have picked. Inside a managed task use\n// TaskWorkspacesRootEnv instead — see resolveDiskUsageRoot.\nfunc ResolveWorkspacesRoot(profile, override string) (string, error) {\n\troot := strings.TrimSpace(os.Getenv(\"MULTICA_WORKSPACES_ROOT\"))\n\tif override != \"\" {\n\t\troot = override\n\t}\n\tif root == \"\" {\n\t\thome, err := os.UserHomeDir()\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"resolve home directory: %w (set MULTICA_WORKSPACES_ROOT to override)\", err)\n\t\t}\n\t\tif profile != \"\" {\n\t\t\troot = filepath.Join(home, \"multica_workspaces_\"+profile)\n\t\t} else {\n\t\t\troot = filepath.Join(home, \"multica_workspaces\")\n\t\t}\n\t}\n\tabs, err := filepath.Abs(root)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"resolve absolute workspaces root: %w\", err)\n\t}\n\treturn abs, nil\n}\n\n// ArtifactPatternsFromEnv returns the configured artifact patternSet — the\n// same list the GC loop consults when it runs the artifact-only cleanup. The\n// disk-usage CLI uses this to make sure the \"artifact size\" it reports\n// matches what the GC would actually reclaim.","sourceCodeStart":603,"sourceCodeEnd":639,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/config.go#L603-L639","documentation":"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.","triggerScenarios":"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.","commonSituations":"Docker containers running as root without HOME, systemd services without Environment=\"HOME=...\", cron jobs, and CI runners with minimal env.","solutions":["Set MULTICA_WORKSPACES_ROOT=/var/lib/multica/workspaces (or any absolute path) for the daemon's environment","Alternatively set HOME explicitly (systemd Environment=, Docker ENV, or -e HOME=...)","For disk-usage, pass the root override directly so no environment is consulted"],"exampleFix":"# before (systemd unit with no HOME)\n[Service]\nExecStart=/usr/local/bin/multica daemon\n\n# after\n[Service]\nEnvironment=\"MULTICA_WORKSPACES_ROOT=/var/lib/multica/workspaces\"\nExecStart=/usr/local/bin/multica daemon","handlingStrategy":"validation","validationCode":"// Guarantee a root exists before the daemon starts.\nfunc ensureWorkspacesRoot() error {\n    if strings.TrimSpace(os.Getenv(\"MULTICA_WORKSPACES_ROOT\")) == \"\" {\n        home, err := os.UserHomeDir()\n        if err != nil {\n            return fmt.Errorf(\"no MULTICA_WORKSPACES_ROOT and no HOME: set MULTICA_WORKSPACES_ROOT\")\n        }\n        _ = home // would build default under home\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["Always set MULTICA_WORKSPACES_ROOT explicitly in service/container definitions","Set HOME in systemd/launchd/docker units that run the daemon","Smoke-test daemon startup in minimal-env CI containers"],"tags":["daemon","environment","home-dir","filesystem"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}