sinelaw/fresh · error

could not read script

Error message

could not read script '{}': {}

What it means

Raised while reading a script for a CLI subcommand: stdin ("-")/no-arg reads stdin, but an explicit path goes through `std::fs::read_to_string`, and any I/O failure is wrapped as `could not read script '{}': {}` with the OS error appended. The wrapper tells you which path failed and why (missing, permission, not a file, invalid UTF-8).

Solutions

  1. Check the path exists and is spelled correctly (ls the exact path).
  2. Pipe the script via stdin instead: pass '-' or omit the path and use `... < script`.
  3. Fix file permissions (chmod/chown) or run as a user with read access.
  4. Re-save the script as UTF-8 — read_to_string rejects non-UTF-8 bytes.

Example fix

// before: failing on a possibly-missing path
let src = std::fs::read_to_string(path).map_err(|e| anyhow::anyhow!("could not read script '{}': {}", path, e))?;
// after: validate before reading and give a targeted message
if !std::path::Path::new(path).is_file() {
    anyhow::bail!("script '{}' does not exist or is not a file", path);
}
let src = std::fs::read_to_string(path).map_err(|e| anyhow::anyhow!("could not read script '{}': {}", path, e))?;
Defensive patterns

Strategy: validation

Validate before calling

fn readable_script(path: &str) -> Result<(), String> {
    let p = std::path::Path::new(path);
    if !p.is_file() { return Err(format!("'{}' is not a file", path)); }
    std::fs::File::open(p).map_err(|e| e.to_string())?;
    Ok(())
}

Try / catch

match read_script(path) {
    Err(e) if e.to_string().starts_with("could not read script") => {
        eprintln!("check the path, permissions, and that the file is UTF-8");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Passing a script file path to the script-taking subcommand when the file cannot be read: nonexistent path, no read permission, it's a directory, or it contains invalid UTF-8.

Common situations: Typo in the script path; relative path resolved from the wrong working directory; script written with a non-UTF-8 encoding; running under a user lacking read permission.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

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

        }
        std::process::exit(1);
    }

    println!("ok");
    Ok(())
}

/// Read a script from a file argument, or stdin when absent or `-`.
fn read_script_source(from: &[&str]) -> AnyhowResult<String> {
    use std::io::Read;
    match from.first().copied() {
        None | Some("-") => {
            let mut buf = String::new();
            std::io::stdin().read_to_string(&mut buf)?;
            Ok(buf)
        }
        Some(path) => std::fs::read_to_string(path)
            .map_err(|e| anyhow::anyhow!("could not read script '{}': {}", path, e)),
    }
}

/// Attach to an existing daemon, starting one if needed
fn run_attach_command(args: &Args) -> AnyhowResult<()> {
    run_attach(
        args.session_name.as_deref(),
        &args.files,
        args.locale.as_deref(),
        args.config.as_deref(),
    )
}

/// `locale` and `config` are the client's own `--locale` and `--config`,
/// forwarded to a daemon we *start* here so those flags survive the hop
/// into the process that actually renders the UI and reads the config.
/// Attaching to an already-running daemon leaves both alone: it is someone
/// else's session, already serving other terminals, the same way an

View on GitHub (pinned to 67894ca546)