{"record":{"id":"bf140addbb8d0896","repo":"charmbracelet/crush","slug":"env-s-requires-a-program","errorCode":null,"errorMessage":"env -S requires a program","messagePattern":"env -S requires a program","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/shell/dispatch.go","lineNumber":342,"sourceCode":"\t}\n\n\tuseSplit := false\n\tif strings.HasPrefix(rest, \"-\") {\n\t\tvar flag, after string\n\t\tif idx := strings.IndexAny(rest, \" \\t\"); idx >= 0 {\n\t\t\tflag = rest[:idx]\n\t\t\tafter = strings.TrimLeft(rest[idx+1:], \" \\t\")\n\t\t} else {\n\t\t\tflag = rest\n\t\t\tafter = \"\"\n\t\t}\n\t\tif flag != \"-S\" {\n\t\t\treturn nil, fmt.Errorf(\"unsupported env flag: %s\", flag)\n\t\t}\n\t\tuseSplit = true\n\t\trest = after\n\t\tif rest == \"\" {\n\t\t\treturn nil, errors.New(\"env -S requires a program\")\n\t\t}\n\t}\n\n\tif rest == \"\" {\n\t\treturn nil, errors.New(\"env: missing program name\")\n\t}\n\n\tvar prog, remainder string\n\tif idx := strings.IndexAny(rest, \" \\t\"); idx >= 0 {\n\t\tprog = rest[:idx]\n\t\tremainder = strings.TrimLeft(rest[idx+1:], \" \\t\")\n\t} else {\n\t\tprog = rest\n\t}\n\n\tsb := &shebang{interpreter: prog}\n\tif remainder != \"\" {\n\t\tif useSplit {","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/shell/dispatch.go#L324-L360","documentation":"In parseEnvShebang, the -S (split-string) flag was given to env but no program followed it, so there is nothing to execute after tokenization. The parser rejects '-S' with an empty remainder.","triggerScenarios":"A shebang such as '#!/usr/bin/env -S' with nothing after the flag, or '#!/usr/bin/env -S   ' (only whitespace).","commonSituations":"Copying portable-shebang examples and dropping the interpreter, or scripts generated for long-argument shebang workarounds where the arguments were stripped.","solutions":["Append the interpreter (and any arguments) after -S: '#!/usr/bin/env -S node --max-old-space-size=4096'.","If no arguments are needed, drop -S entirely: '#!/usr/bin/env node'.","Lint scripts for env shebangs that end with a flag and no program."],"exampleFix":"// before\n#!/usr/bin/env -S\n// after\n#!/usr/bin/env -S python3 -u","handlingStrategy":"validation","validationCode":"line, _ := bufio.NewReader(f).ReadString('\\n')\nif strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), \"#!\")) == \"/usr/bin/env -S\" || strings.HasSuffix(strings.TrimSpace(line), \"-S\") {\n    return errors.New(\"env -S shebang missing program\")\n}","typeGuard":null,"tryCatchPattern":"if err := dispatch(script); err != nil {\n    if strings.Contains(err.Error(), \"-S requires a program\") {\n        return fmt.Errorf(\"%s: -S needs an interpreter argument\", script)\n    }\n    return err\n}","preventionTips":["Ensure a program follows -S in every env shebang.","Drop -S when no interpreter arguments are needed.","Add a shebang linter to catch flag-only env lines."],"tags":["shell","shebang","env","malformed-input"],"backgroundTag":"invalid-shebang","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}