charmbracelet/crush · error

env: missing program name

Error message

env: missing program name

What it means

parseEnvShebang found an '#!/usr/bin/env' style shebang with no interpreter program named after env. env needs at least a program name to execute, so the parser rejects the line.

Source

Thrown at internal/shell/dispatch.go:323

// isEnvShebang reports whether the shebang path targets `env`. We accept
// both common absolute paths and a bare `env` so that unusual setups
// (NixOS, BSDs) still work.
func isEnvShebang(p string) bool {
	if p == "/usr/bin/env" || p == "/bin/env" {
		return true
	}
	return filepath.Base(p) == "env"
}

// parseEnvShebang handles `/usr/bin/env` rewriting. Without `-S`, the
// remainder after the program name is a single argv[1] (kernel
// single-arg semantics via env, even though real env would fail to find a
// program named "bash -x"). With `-S`, the remainder is tokenized on
// whitespace. Any other `env` flag is rejected — forwarding unknown flags
// to a /usr/bin/env on disk is a subtle portability footgun we don't want.
func parseEnvShebang(rest string) (*shebang, error) {
	if rest == "" {
		return nil, errors.New("env: missing program name")
	}

	useSplit := false
	if strings.HasPrefix(rest, "-") {
		var flag, after string
		if idx := strings.IndexAny(rest, " \t"); idx >= 0 {
			flag = rest[:idx]
			after = strings.TrimLeft(rest[idx+1:], " \t")
		} else {
			flag = rest
			after = ""
		}
		if flag != "-S" {
			return nil, fmt.Errorf("unsupported env flag: %s", flag)
		}
		useSplit = true
		rest = after
		if rest == "" {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Add the interpreter name after env: e.g. '#!/usr/bin/env bash' or '#!/usr/bin/env -S python3 -u'.
  2. If using -S split-mode, make sure the program follows the flag on the same line.
  3. Validate the script's first line before dispatching it in tooling.

Example fix

// before
#!/usr/bin/env
// after
#!/usr/bin/env bash
Defensive patterns

Strategy: validation

Validate before calling

line, _ := bufio.NewReader(f).ReadString('\n')
rest := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), "#!"))
if strings.HasPrefix(rest, "#!/usr/bin/env") && strings.TrimSpace(strings.TrimPrefix(rest, "#!/usr/bin/env")) == "" {
    return errors.New("env shebang missing interpreter")
}

Try / catch

if err := dispatch(script); err != nil {
    if strings.Contains(err.Error(), "missing program name") {
        return fmt.Errorf("%s: add an interpreter after /usr/bin/env", script)
    }
    return err
}

Prevention

When it happens

Trigger: A shebang like '#!/usr/bin/env' (nothing after), or '#!/usr/bin/env -S' where -S consumed the rest and left an empty program string.

Common situations: A truncated or hand-edited shebang line missing the interpreter (e.g. someone deleted 'python3' from '#!/usr/bin/env python3').

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/695e3f925194d986. Report an issue: GitHub.