charmbracelet/crush · error
empty shebang
Error message
empty shebang
What it means
parseShebang could not extract an interpreter path from the first line of a script: after stripping CR and leading whitespace, the shebang line was effectively empty. This guards against files whose first line is just '#!' or whitespace.
Source
Thrown at internal/shell/dispatch.go:281
// parseShebang extracts the interpreter invocation from probe. It tolerates
// CRLF line endings and a single leading space between `#!` and the path.
// env special-cases: `/usr/bin/env NAME [args...]` unwraps to NAME with
// kernel single-arg semantics; `-S` enables tokenized argument splitting.
func parseShebang(probe []byte) (*shebang, error) {
if !hasShebang(probe) {
return nil, errors.New("not a shebang")
}
line := probe[2:]
// Take up to the first newline.
if idx := bytes.IndexByte(line, '\n'); idx >= 0 {
line = line[:idx]
}
// Strip trailing CR (CRLF-authored scripts).
line = bytes.TrimRight(line, "\r")
// Strip leading whitespace ("#! /usr/bin/env bash" is legal).
line = bytes.TrimLeft(line, " \t")
if len(line) == 0 {
return nil, errors.New("empty shebang")
}
var pathStr, rest string
if idx := bytes.IndexAny(line, " \t"); idx >= 0 {
pathStr = string(line[:idx])
rest = strings.TrimLeft(string(line[idx+1:]), " \t")
} else {
pathStr = string(line)
}
if isEnvShebang(pathStr) {
return parseEnvShebang(rest)
}
// Literal-path shebang: kernel semantics pass the remainder as a
// single argv[1], not tokenized.
sb := &shebang{interpreter: pathStr}
if rest != "" {View on GitHub (pinned to 7944b8e522)
Solutions
- Fix the script's first line to a valid shebang like '#!/bin/bash' or '#!/usr/bin/env bash'.
- Remove the empty shebang line entirely if the script doesn't need one.
- Check for CRLF authoring issues and correct the shebang line ending.
- If the file is generated, fix the generator template to emit a complete shebang.
Example fix
#!/bin/bash // before #! #!/bin/sh -e // after #!/bin/sh -e
Defensive patterns
Strategy: validation
Validate before calling
first, _ := bufio.NewReader(f).ReadString('\n')
line := strings.TrimSpace(strings.TrimRight(first, "\r"))
if !strings.HasPrefix(line, "#!") || len(strings.TrimSpace(line[2:])) == 0 {
return errors.New("script has empty/invalid shebang")
} Type guard
func hasValidShebang(line []byte) bool {
line = bytes.TrimLeft(bytes.TrimRight(line, "\r"), " \t")
return len(line) > 2
} Try / catch
if err := dispatchShebang(script); err != nil {
if strings.Contains(err.Error(), "empty shebang") {
return fmt.Errorf("script %s: fix line 1 with a real interpreter", script)
}
return err
} Prevention
- Always start scripts with a full '#!/path/to/interp' line.
- Lint generated scripts for bare '#!' lines.
- Watch for CRLF-authored scripts mangling shebangs.
When it happens
Trigger: Dispatching a script whose first line is '#!', '#! ' (only whitespace after #!), or is otherwise blank after trimming.
Common situations: A hand-written or generated script with a malformed shebang line, or a file accidentally truncated so only '#!' remains on line 1.
Related errors
- env: missing program name
- env -S requires a program
- interpreter %q not found in PATH
- interpreter %q not found and %q not in PATH
- unsupported env flag: %s
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/ecc3d069da9c44af.
Report an issue: GitHub.