{"record":{"id":"3cd3700478bd4f26","repo":"charmbracelet/crush","slug":"could-not-parse-s-w","errorCode":null,"errorMessage":"could not parse %s: %w","messagePattern":"could not parse (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/shell/dispatch.go","lineNumber":386,"sourceCode":"\n// runShellSource parses path's contents as POSIX shell and runs it\n// in-process via a nested interp.Runner. It reuses the parent runner's cwd,\n// env, and stdio, and rebuilds the Crush handler stack so builtins and the\n// dispatch handler itself remain available to anything the script invokes.\n// Positional parameters ($1, $2, …) come from args[1:].\n//\n// This is the only branch that reads the full file; probeFile keeps its\n// read to probeWindow bytes so the binary/shebang paths never touch more\n// than 128 bytes of I/O.\nfunc runShellSource(ctx context.Context, path string, args []string, blockFuncs []BlockFunc) error {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfile, err := syntax.NewParser().Parse(bytes.NewReader(data), path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not parse %s: %w\", path, err)\n\t}\n\n\thc := interp.HandlerCtx(ctx)\n\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}","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/shell/dispatch.go#L368-L404","documentation":"runShellSource wraps a syntax parse failure when executing a file's contents as POSIX shell in-process via mvdan.cc/sh. The file could not be parsed by syntax.NewParser().Parse, so the wrapped interpreter never runs it. The underlying mvdan.cc/sh parse error is included via %w.","triggerScenarios":"dispatchShebang or the binary/exec handler resolves a script to shell source and runShellSource reads it; the file contains syntax invalid for mvdan.cc/sh (POSIX-ish shell), such as unbalanced quotes, unsupported bashisms, or heredoc mistakes.","commonSituations":"Scripts using bash-4+ features the parser rejects; corrupted scripts from interrupted downloads; CRLF or encoding issues producing stray characters; scripts generated with template placeholders left unexpanded.","solutions":["Read the wrapped mvdan.cc/sh error (includes line/column) and fix the syntax at that location.","Validate the script locally with `sh -n script.sh` (or bash -n if bashisms are intended) before shipping.","If the script requires bash-only syntax, ensure the shebang targets bash and the dispatcher executes it as such.","Regenerate or re-download the file if it appears truncated or templated incorrectly."],"exampleFix":"// before (invalid: unmatched quote)\necho \"hello world\n// after\necho \"hello world\"","handlingStrategy":"try-catch","validationCode":"if err := exec.Command(\"sh\", \"-n\", scriptPath).Run(); err != nil {\n    // script has syntax problems; fix before executing via dispatcher\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.HasPrefix(err.Error(), \"could not parse \") {\n        // parse failure: log path + wrapped mvdan.cc/sh position info\n    }\n}","preventionTips":["Run `sh -n` (or bash -n) on scripts in CI.","Keep scripts POSIX-compatible or target bash explicitly.","Avoid generating scripts via string templating without validation.","Watch for CRLF/encoding corruption when scripts cross editors."],"tags":["shell","syntax-error","parsing","script"],"backgroundTag":"shell-parse-error","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}