denoland/deno · error · Error

invalid doc test hashbang: #!/bin/sh (binary basename needs

Error message

invalid doc test hashbang: #!/bin/sh (binary basename needs to be 'deno')

What it means

With `deno test --doc`, every fenced code block in a doc comment becomes a generated Deno.test. If the fence starts with a shebang, parse_shebang() (cli/util/extract.rs:554) tokenizes it and searches the tokens for an executable whose file stem is exactly "deno". When none is found (e.g. #!/bin/sh), the extractor still emits the test but its body immediately throws Error("invalid doc test hashbang: ... (binary basename needs to be 'deno')") so the example fails loudly instead of silently running with the wrong permissions.

Source

Thrown at cli/util/extract.rs:2058

      },
      // Unparseable shebang fails the test, naming the reason.
      Test {
        input: Input {
          source: r#"
/**
 * ```ts
 * #!/bin/sh
 * foo();
 * ```
 */
export function foo() {}
"#,
          specifier: "file:///main.ts",
        },
        expected: vec![Expected {
          source: r#"import { foo } from "file:///main.ts";
Deno.test("file:///main.ts#3-7.ts", async ()=>{
    throw new Error("invalid doc test hashbang: #!/bin/sh (binary basename needs to be 'deno')");
    foo();
});
"#,
          specifier: "file:///main.ts#3-7.ts",
          media_type: MediaType::TypeScript,
        }],
      },
      // A scoped `--deny-*` can't be modelled, so the test is made to fail
      // rather than run with broader permissions than the shebang declares.
      Test {
        input: Input {
          source: r#"
/**
 * ```ts
 * #!/usr/bin/env -S deno run --allow-read --deny-read=/etc
 * foo();
 * ```
 */

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Remove the shebang line from the fenced example - plain code needs none
  2. Change it to a shebang the parser recognizes, e.g. #!/usr/bin/env -S deno run --allow-read=. (the binary basename must be exactly 'deno', not 'deno-canary')
  3. Mark the fence to be skipped: ```ts ignore as the fence info string

Example fix

// before
/**
 * ```ts
 * #!/bin/sh
 * foo();
 * ```
 */

// after
/**
 * ```ts
 * foo();
 * ```
 */
// or keep the shebang example but skip it: ```ts ignore
Defensive patterns

Strategy: validation

Validate before calling

// CI check: find shebangs inside doc comments that do not target a 'deno' binary
grep -rn --include='*.ts' -B2 '#!/bin/\(sh\|bash\)\|env node' src/ | grep -A2 '^.*\* ```' || true

Prevention

When it happens

Trigger: An exported function's JSDoc contains a ```ts fence whose first line is #!/bin/sh, #!/bin/bash, or #!/usr/bin/env node, and the test suite runs with deno test --doc.

Common situations: Documenting CLI wrapper scripts or shell-invocable examples inside library doc comments; copy-pasting runnable examples from README files that carry sh shebangs; CI doc-test jobs that start failing after such an example is added.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/43e6bfe64e13f725. Report an issue: GitHub.