sinelaw/fresh · error

empty script: pass a file, or pipe the source on stdin

Error message

empty script: pass a file, or pipe the source on stdin

What it means

script_run reads the script source from files/stdin via read_script_source and bails when the resulting source is empty or whitespace-only. An empty script has nothing to evaluate, so it is rejected before submission to the editor.

Solutions

  1. Pipe the script on stdin: `fresh --script-file - < myscript.js`, or use a tty-interactive editor.
  2. Pass a non-empty file path with actual JS source in it.
  3. Verify the file size / content before invoking (`wc -c script.js`).
  4. Fix the upstream step that was supposed to generate the script.

Example fix

# before
fresh --script-file -          # empty stdin
# after
fresh --script-file - < script.js
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const src = process.argv[3] === '-' ? fs.readFileSync(0, 'utf8') : fs.readFileSync(process.argv[3], 'utf8');
if (!src.trim()) { console.error('script source is empty: pass a file with content or pipe stdin'); process.exit(1); }

Prevention

When it happens

Trigger: `fresh --script-file` pointing at an empty (or whitespace/comment-only) file; piping empty stdin, e.g. running `fresh --script-file -` in a terminal with no piped input; an empty here-doc (`<<EOF\nEOF`).

Common situations: Forgot to redirect a file into stdin (`fresh --script-file -` without `< script.js`); script file created but never saved; a build step that produced a zero-byte script; variable expansion that emptied the source.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/f40dfd54d4b7362a. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/main.rs:4247

        .join("types");
    println!("{}", dir.join("fresh.d.ts").display());
    println!("{}", dir.join("plugins.d.ts").display());
    Ok(())
}

/// `fresh --cmd script run [FILE|-]` — evaluate a script in the editor.
///
/// The source comes from a file or stdin rather than argv: a script is
/// multi-line and full of quotes, and threading that through a shell's argument
/// vector mangles it. `fresh --cmd script run < s.ts`, a heredoc, or an explicit
/// path all work.
///
/// Whatever the script returns is printed as JSON; a throw becomes a non-zero
/// exit with the message on stderr.
fn script_run(session: Option<&str>, from: &[&str]) -> AnyhowResult<()> {
    let source = read_script_source(from)?;
    if source.trim().is_empty() {
        anyhow::bail!("empty script: pass a file, or pipe the source on stdin");
    }
    submit_script(session, source, false)
}

/// Send `source` to a live editor's script channel and report the outcome:
/// whatever the script returned on stdout, a throw on stderr with exit 1.
///
/// Every verb below is a thin wrapper over this. The script channel is
/// already the authorized, window-scoped, capability-checked way into a
/// running editor, so a new verb needs a new *script*, not a new socket
/// message — and the verb inherits the token check for free.
///
/// `unwrap_string` decodes a JSON string result before printing it. `script
/// run` leaves its output verbatim (a script's return value is data, and the
/// caller asked for JSON); the convenience verbs return prose meant to be
/// read, where the surrounding quotes and `\n` escapes would be noise.
fn submit_script(session: Option<&str>, source: String, unwrap_string: bool) -> AnyhowResult<()> {
    use fresh::server::protocol::ClientControl;

View on GitHub (pinned to 67894ca546)