{"record":{"id":"9d72695520a39b58","repo":"charmbracelet/crush","slug":"arg-d-w","errorCode":null,"errorMessage":"arg %d: %w","messagePattern":"arg (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/config.go","lineNumber":458,"sourceCode":"}\n\n// ResolvedArgs returns m.Args with every element expanded through the\n// given resolver. A fresh slice is allocated; m.Args is never mutated.\n// On the first resolution failure it returns nil and an error\n// identifying the offending positional index; the inner resolver error\n// is already sanitized by ResolveValue and is wrapped with %w so\n// errors.Is/As continues to work.\n//\n// See ResolvedEnv for guidance on picking a resolver.\nfunc (m MCPConfig) ResolvedArgs(r VariableResolver) ([]string, error) {\n\tif len(m.Args) == 0 {\n\t\treturn nil, nil\n\t}\n\tout := make([]string, len(m.Args))\n\tfor i, a := range m.Args {\n\t\tv, err := r.ResolveValue(a)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"arg %d: %w\", i, err)\n\t\t}\n\t\tout[i] = v\n\t}\n\treturn out, nil\n}\n\n// ResolvedURL returns m.URL expanded through the given resolver. The\n// receiver is not mutated. Errors from the resolver are already\n// sanitized by ResolveValue and are wrapped with %w for errors.Is/As.\n//\n// URLs run through the same shell-expansion pipeline as the other\n// fields, so a literal '$' (e.g. OData query strings containing\n// $filter/$select) must be escaped as '\\$' or '${DOLLAR:-$}' to avoid\n// being interpreted as a variable reference. Same constraint already\n// applies to command, args, env, and headers.\n//\n// See ResolvedEnv for guidance on picking a resolver.\nfunc (m MCPConfig) ResolvedURL(r VariableResolver) (string, error) {","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/config.go#L440-L476","documentation":"MCPConfig.ResolvedArgs resolves each entry of the MCP server's Args list through VariableResolver.ResolveValue, which expands template variables (e.g. {{env.VAR}}) in config values. If resolving any single argument fails, it is wrapped as `arg <index>: <cause>`. Typical causes are references to undefined environment variables or secrets that cannot be found.","triggerScenarios":"Starting or resolving an MCP server configured in crushrc whose `args` contain an unresolvable template variable — most commonly `{{env.SOME_VAR}}` where SOME_VAR is unset, or an invalid variable reference syntax.","commonSituations":"Defining an MCP stdio server whose args reference an env var that exists in one shell but not the one crush runs in; CI environments missing a secret; typo in the variable key inside {{...}}.","solutions":["Read the wrapped cause and the arg index to find the offending argument.","Export the referenced environment variable (e.g. export API_KEY=...) before launching crush, or put it in your shell profile.","Define the value via crush's secrets/env config instead of a bare {{env.X}} reference.","Fix typos in the {{...}} variable name in the MCP args in crushrc."],"exampleFix":"// before (crushrc)\nmcp myserver --command npx --args '-y','pkg','--key','{{env.MY_API_KEY}}' // MY_API_KEY unset\n// after\nexport MY_API_KEY=sk-...  # then rerun crush","handlingStrategy":"validation","validationCode":"# verify every {{env.X}} referenced in MCP args exists before starting crush\ngrep -o '{{env\\.[A-Z_]*}}' crushrc | sed 's/{{env\\.//;s/}}//' | sort -u | while read -r v; do\n  [ -n \"${!v+x}\" ] || echo \"missing env var: $v\"\ndone","typeGuard":null,"tryCatchPattern":"args, err := m.ResolvedArgs(resolver)\nif err != nil {\n    var miss *MissingEnvError // example typed cause from the resolver\n    if errors.As(err, &miss) {\n        return fmt.Errorf(\"set %s before starting MCP server\", miss.Name)\n    }\n    return err\n}","preventionTips":["Export all env vars referenced by MCP args in your shell profile.","Keep env var names consistent between crushrc and CI secrets.","Prefer crush's secrets configuration over ad-hoc {{env.X}} where possible.","Dry-run config loading (start crush) after editing MCP args."],"tags":["config","mcp","variable-resolution","env"],"backgroundTag":"unresolved-config-variable","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}