epi052/feroxbuster · error

Could not print banner

Error message

Could not print banner

What it means

Before scanning, wrapped_main asks the banner system to check for updates and print the banner to stderr; if banner.print_to returns an error, it cleans up and bails with fmt_err("Could not print banner"). The update-check failure is deliberately ignored (let _), but an actual failure rendering/printing the banner aborts the run.

Solutions

  1. Ensure stderr is open and writable (check redirections like 2>/dev/null or closed fds)
  2. Run in a normal terminal or fix TERM/locale environment variables
  3. Update ferox — newer releases handle odd terminal states more gracefully
  4. If it persists, capture stderr to a file to see the underlying writer error and report it

Example fix

// before
ferox -u https://t.com 2>&1-   # closed stderr
// after
ferox -u https://t.com 2>ferox.log
Defensive patterns

Strategy: try-catch

Validate before calling

if (!process.stderr.writable) throw new Error('stderr must be open and writable');

Try / catch

try { ... } catch (e) { if (String(e).includes('Could not print banner')) { /* check stderr redirection/terminal state; run with stderr redirected to a file */ } }

Prevention

When it happens

Trigger: banner.print_to fails while writing the banner to the provided stderr handle — e.g. the terminal/stderr writer errors (closed descriptor, unsupported terminal state) or banner rendering fails on the given config.

Common situations: Running in restricted environments (CI, docker with closed stdout/stderr), weird TERM settings or non-TTY sinks, or output redirection to a file/pipe that is closed (broken pipe).

Related errors


AI-assisted analysis of epi052/feroxbuster@1f595dab5c (2026-09-13). Data as JSON: /api/errors/9480342e891a541b. Report an issue: GitHub.

Appendix: source

Thrown at src/main.rs:548

    // wait until the parallel branch has been handled before sending the UpdateTargets command
    // this ensures that only the targets being scanned are sent to the Stats object
    //
    // if sent before the parallel branch is handled, the Stats object will have duplicate
    // targets
    handles.stats.send(UpdateTargets(targets.clone()))?;

    if matches!(config.output_level, OutputLevel::Default) {
        // only print banner if output level is default (no banner on --quiet|--silent)
        let std_stderr = stderr(); // std::io::stderr

        let mut banner = Banner::new(&targets, &config);

        // only interested in the side-effect that sets banner.update_status
        let _ = banner.check_for_updates(UPDATE_URL, handles.clone()).await;

        if banner.print_to(std_stderr, config.clone()).is_err() {
            clean_up(handles, tasks).await?;
            bail!(fmt_err("Could not print banner"));
        }
    }

    {
        let send_to_file = !config.output.is_empty();

        // The TermOutHandler spawns a FileOutHandler, so errors in the FileOutHandler never bubble
        // up due to the TermOutHandler never awaiting the result of FileOutHandler::start (that's
        // done later here in main). sync checks that the tx/rx connection to the file handler works
        if send_to_file && handles.output.sync(send_to_file).await.is_err() {
            // output file specified and file handler could not initialize
            clean_up(handles, tasks).await?;
            let msg = format!("Couldn't start {} file handler", config.output);
            bail!(fmt_err(&msg));
        }
    }

    // discard non-responsive targets

View on GitHub (pinned to 1f595dab5c)