{"record":{"id":"9818418904cff87f","repo":"multica-ai/multica","slug":"resolve-absolute-workspaces-root-w","errorCode":null,"errorMessage":"resolve absolute workspaces root: %w","messagePattern":"resolve absolute workspaces root: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/config.go","lineNumber":631,"sourceCode":"func 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.\nfunc ArtifactPatternsFromEnv() []string {\n\treturn patternsFromEnv(\"MULTICA_GC_ARTIFACT_PATTERNS\", DefaultGCArtifactPatterns)\n}\n\n// patternsFromEnv reads a comma-separated list from env. Patterns containing\n// path separators are silently dropped — the GC artifact cleanup only matches\n// directory basenames, never paths, so a pattern like \"foo/bar\" is meaningless\n// and accepting it would just be a footgun.\nfunc patternsFromEnv(name string, defaults []string) []string {\n\traw := strings.TrimSpace(os.Getenv(name))","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/config.go#L613-L649","documentation":"The tail of ResolveWorkspacesRoot: after a root value is determined (from env, override, or $HOME), filepath.Abs(root) failed. Abs only fails when os.Getwd fails and the path is relative — i.e. the process's working directory was deleted or is unreadable, and the configured root was relative rather than absolute.","triggerScenarios":"Setting MULTICA_WORKSPACES_ROOT to a relative path (e.g. 'workspaces') while the daemon's cwd has been removed (common in container setups that rm the workdir, or when launched from a deleted temp dir).","commonSituations":"Containers where WORKDIR is removed at runtime, relative paths in config combined with unusual launch contexts, or chdir-based test harnesses.","solutions":["Set MULTICA_WORKSPACES_ROOT to an absolute path (/data/workspaces)","Ensure the daemon's working directory exists for the whole process lifetime","If a launcher script cds into a temp dir, launch the daemon from a stable directory instead"],"exampleFix":"# before\nexport MULTICA_WORKSPACES_ROOT=workspaces # relative\n# after\nexport MULTICA_WORKSPACES_ROOT=/var/lib/multica/workspaces # absolute","handlingStrategy":"validation","validationCode":"// Reject relative roots before use.\nif !filepath.IsAbs(root) {\n    abs, err := filepath.Abs(root) // can fail if cwd is gone\n    if err != nil {\n        return fmt.Errorf(\"relative workspaces root %q and cwd unavailable: use an absolute path\", root)\n    }\n    root = abs\n}","typeGuard":null,"tryCatchPattern":"Catch and re-prompt with the requirement 'provide an absolute MULTICA_WORKSPACES_ROOT'; not retryable within the same process.","preventionTips":["Use absolute paths in all daemon configuration","Keep the daemon's working directory alive for the process lifetime","In containers, prefer env-configured absolute roots over defaults"],"tags":["daemon","filesystem","relative-path","cwd"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}