multica-ai/multica · error

invalid %s: %w

Error message

invalid %s: %w

What it means

shellArgsFromEnv parses agent-argument env vars (MULTICA_CLAUDE_ARGS, MULTICA_CODEX_ARGS, MULTICA_CODEBUDDY_ARGS, ...) with shellwords; unbalanced quotes, a trailing backslash, or other shell-syntax errors make Parse return an error, which is wrapped with the offending variable's name. The value is treated as a shell command line, not a raw string.

Source

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

	out := make([]string, 0, len(parts))
	for _, p := range parts {
		p = strings.TrimSpace(p)
		if p == "" || strings.ContainsAny(p, "/\\") {
			continue
		}
		out = append(out, p)
	}
	return out
}

func shellArgsFromEnv(name string) ([]string, error) {
	raw := strings.TrimSpace(os.Getenv(name))
	if raw == "" {
		return nil, nil
	}
	args, err := shellwords.Parse(raw)
	if err != nil {
		return nil, fmt.Errorf("invalid %s: %w", name, err)
	}
	return args, nil
}

// resolveAgentExecutablePath returns the executable entry point the daemon
// should keep for an agent command. Bare command names are pinned to the path
// resolved during startup so later PATH changes cannot redirect task launches.
// Ordinary executables are pinned to their concrete target; entrypoints owned
// by a name-dispatching shim keep the command name the manager needs to select
// the right package (see discoveredExecutablePath).
// On Windows this deliberately keeps the stable discovered junction path;
// resolveAgentEntryWithHeal follows it for each launch so installer upgrades
// that retarget a still-live junction take effect without a daemon restart.
// When ~/.multica/hooks shadows a real agent binary, skip that hooks directory:
// previously generated hook wrappers can execute the same command name and
// recurse forever if the daemon records or launches the wrapper.
func resolveAgentExecutablePath(cmd string) (string, error) {
	resolved, err := exec.LookPath(cmd)

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Balance all quotes in the env value: MULTICA_CLAUDE_ARGS='--model "opus-4" --verbose'
  2. Escape literal quotes as \" and avoid trailing backslashes; wrap Windows paths in quotes ('"C:\path"')
  3. After fixing, restart the daemon — config is only read at startup

Example fix

# before
export MULTICA_CLAUDE_ARGS="--model \"opus-4 --verbose"   # unbalanced quotes
# after
export MULTICA_CLAUDE_ARGS="--model opus-4 --verbose"
Defensive patterns

Strategy: validation

Validate before calling

// Dry-run the shellwords parse before handing the env to the daemon.
for _, name := range []string{"MULTICA_CLAUDE_ARGS", "MULTICA_CODEX_ARGS", "MULTICA_CODEBUDDY_ARGS"} {
    if raw := strings.TrimSpace(os.Getenv(name)); raw != "" {
        if _, err := shellwords.Parse(raw); err != nil {
            return fmt.Errorf("%s has invalid shell syntax: %w", name, err)
        }
    }
}

Try / catch

Catch at config load; parse the env value with shellwords yourself in a CLI lint step ('multica config check') to surface quoting errors before daemon start.

Prevention

When it happens

Trigger: Setting MULTICA_CLAUDE_ARGS='--model "opus' (unclosed quote) or MULTICA_CODEX_ARGS='--flag value\' (trailing escape). Any of the *ARGS env vars with invalid shell word syntax fails daemon startup at config load.

Common situations: Quoting mistakes when nesting quotes ('--prompt "say \"hi\""'), Windows users copying cmd.exe syntax (%VAR% or doubled quotes) into a POSIX-style shellwords value, trailing backslashes from path arguments.

Related errors


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