{"record":{"id":"ae27899fef74ca3a","repo":"charmbracelet/crush","slug":"could-not-build-runner-for-s-w","errorCode":null,"errorMessage":"could not build runner for %s: %w","messagePattern":"could not build runner for (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/shell/dispatch.go","lineNumber":408,"sourceCode":"\n\topts := []interp.RunnerOption{\n\t\tinterp.StdIO(hc.Stdin, hc.Stdout, hc.Stderr),\n\t\tinterp.Interactive(false),\n\t\tinterp.Env(hc.Env),\n\t\tinterp.Dir(hc.Dir),\n\t\texecHandlerOption(blockFuncs),\n\t}\n\tif len(args) > 1 {\n\t\t// Params with a leading \"--\" avoids any of args[1:] being\n\t\t// misinterpreted as set-options (e.g. a user passing \"-e\" as\n\t\t// a positional arg to their script).\n\t\tparams := append([]string{\"--\"}, args[1:]...)\n\t\topts = append(opts, interp.Params(params...))\n\t}\n\n\trunner, err := interp.New(opts...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not build runner for %s: %w\", path, err)\n\t}\n\treturn runner.Run(ctx, file)\n}\n\n// execEnvList converts an expand.Environ to the []string form that\n// os/exec.Cmd.Env expects. Only exported string variables are included,\n// matching what a real shell would pass to a child process.\nfunc execEnvList(env expand.Environ) []string {\n\tvar out []string\n\tenv.Each(func(name string, vr expand.Variable) bool {\n\t\tif vr.Exported && vr.Kind == expand.String {\n\t\t\tout = append(out, name+\"=\"+vr.Str)\n\t\t}\n\t\treturn true\n\t})\n\treturn out\n}\n","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/shell/dispatch.go#L390-L426","documentation":"runShellSource wraps a failure from interp.New when constructing the nested interpreter runner that executes a parsed shell file. Runner construction validates options (StdIO, Env, Dir, Params, exec handler); an invalid combination makes the runner unbuildable before any script line executes.","triggerScenarios":"After a successful syntax parse, interp.New(opts...) returns an error — e.g. invalid interp.Params values, an unusable interp.Dir, or a misconfigured exec handler option — while dispatching a shell script in-process.","commonSituations":"Programmatic misconfiguration of runner options; a parent HandlerCtx carrying a bad working directory; regression in custom execHandlerOption wiring after refactors; rare mvdan.cc/sh version incompatibilities.","solutions":["Inspect the wrapped mvdan.cc/sh error to identify which runner option is invalid.","Verify the parent interp.HandlerCtx Dir/Env values are sane (existing directory, well-formed env list).","Check that args passed via interp.Params don't include malformed set-options; the code prefixes \"--\" to guard this.","If it persists after a mvdan.cc/sh upgrade, pin the previous version and report the incompatibility."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if st, err := os.Stat(dir); err != nil || !st.IsDir() {\n    // bad Dir option would break interp.New — fix before dispatch\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.HasPrefix(err.Error(), \"could not build runner for \") {\n        // runner construction failed; inspect wrapped interp.New error\n    }\n}","preventionTips":["Keep runner options (Dir, Env, Params) derived from validated values.","Preserve the \"--\" prefix when forwarding positional params.","Test the dispatch path after mvdan.cc/sh upgrades.","Keep exec handler wiring in one reviewed place."],"tags":["shell","interpreter","runner","configuration"],"backgroundTag":"shell-runner-init-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}