{"record":{"id":"b156a49773d176aa","repo":"multica-ai/multica","slug":"resolve-task-local-cli-config-root-w","errorCode":null,"errorMessage":"resolve task-local CLI config root: %w","messagePattern":"resolve task-local CLI config root: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/cli/config.go","lineNumber":333,"sourceCode":"\n// SaveCLIConfigForProfile writes the CLI config for the given profile.\nfunc SaveCLIConfigForProfile(cfg CLIConfig, profile string) error {\n\tpath, err := CLIConfigPathForProfile(profile)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdir := filepath.Dir(path)\n\tdirMode := os.FileMode(0o755)\n\tif strings.TrimSpace(os.Getenv(TaskConfigRootEnv)) != \"\" {\n\t\tdirMode = 0o700\n\t}\n\tif err := os.MkdirAll(dir, dirMode); err != nil {\n\t\treturn fmt.Errorf(\"create CLI config directory: %w\", err)\n\t}\n\tif dirMode == 0o700 {\n\t\troot, _, err := multicaConfigRoot()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"resolve task-local CLI config root: %w\", err)\n\t\t}\n\t\tfor current := dir; ; current = filepath.Dir(current) {\n\t\t\tif err := os.Chmod(current, 0o700); err != nil {\n\t\t\t\treturn fmt.Errorf(\"restrict task-local CLI config directory: %w\", err)\n\t\t\t}\n\t\t\tif current == root {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tparent := filepath.Dir(current)\n\t\t\tif parent == current {\n\t\t\t\treturn fmt.Errorf(\"task-local CLI config directory %q escapes root %q\", dir, root)\n\t\t\t}\n\t\t}\n\t}\n\tdata, err := json.MarshalIndent(cfg, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"encode CLI config: %w\", err)\n\t}","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/cli/config.go#L315-L351","documentation":"While saving with MULTICA_TASK_CONFIG_ROOT set, the code needs the task-local root to chmod-restrict the created directories to 0700, but multicaConfigRoot() failed. In practice the only failure mode at this point is the env var being non-absolute (or the home directory being unresolvable in the fallback path).","triggerScenarios":"MULTICA_TASK_CONFIG_ROOT set to a relative path (e.g. 'multica-tasks' or './run') while saving the CLI config; or the env var unset and os.UserHomeDir() failing because $HOME is empty.","commonSituations":"A daemon or wrapper exporting MULTICA_TASK_CONFIG_ROOT with a relative value; CI containers where HOME is not set; envsubst/scripts accidentally stripping the leading slash.","solutions":["Set MULTICA_TASK_CONFIG_ROOT to an absolute path (leading '/')","If the task-local mode is unintended, unset MULTICA_TASK_CONFIG_ROOT entirely","In minimal containers/CI, ensure HOME is set so the non-task fallback can resolve","Validate the env var at daemon startup before spawning CLI subprocesses that inherit it"],"exampleFix":"# before\nexport MULTICA_TASK_CONFIG_ROOT=multica/tasks\n\n# after\nexport MULTICA_TASK_CONFIG_ROOT=/var/lib/multica/tasks","handlingStrategy":"validation","validationCode":"if root := strings.TrimSpace(os.Getenv(\"MULTICA_TASK_CONFIG_ROOT\")); root != \"\" && !filepath.IsAbs(root) {\n\t// reject/fix the env var before any CLI invocation\n\tlog.Fatal(\"MULTICA_TASK_CONFIG_ROOT must be an absolute path\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate MULTICA_TASK_CONFIG_ROOT is absolute at daemon startup","Use realpath when constructing the env var in scripts","Ensure HOME is set in containers where the CLI runs"],"tags":["environment","config","paths","go"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}