rtk-ai/rtk · error
Failed to read stdin: {}
Error message
Failed to read stdin: {} What it means
Filtered pipe mode reads ALL of stdin into a String via read_to_string, which requires the stream to be valid UTF-8; any IO error or invalid byte sequence is reported as `Failed to read stdin: {e}`. The read is capped at RAW_CAP+1 bytes (10 MiB) so oversize input fails on the explicit size check, not here — this error is about readability/IO, not size.
Source
Thrown at src/cmds/system/pipe_cmd.rs:257
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| filter_fn(input)))
.unwrap_or_else(|_| {
eprintln!("[rtk] warning: filter panicked — passing through raw output");
input.to_string()
})
}
pub fn run(filter_name: Option<&str>, passthrough: bool) -> Result<()> {
if passthrough {
std::io::copy(&mut std::io::stdin(), &mut std::io::stdout())
.map_err(|e| anyhow::anyhow!("Failed to relay stdin: {}", e))?;
return Ok(());
}
let mut buf = String::new();
std::io::stdin()
.take((RAW_CAP + 1) as u64)
.read_to_string(&mut buf)
.map_err(|e| anyhow::anyhow!("Failed to read stdin: {}", e))?;
if buf.len() > RAW_CAP {
anyhow::bail!("stdin exceeds {} byte limit", RAW_CAP);
}
let filter_fn = match filter_name {
Some(name) => resolve_filter(name).ok_or_else(|| {
anyhow::anyhow!(
"Unknown filter '{}'. Available: cargo-test, pytest, go-test, go-build, \
tsc, vitest, grep, rg, find, fd, git-log, git-diff, git-status, \
log, mypy, ruff-check, ruff-format, prettier, phpunit, pest, \
paratest, php-test, ecs, phpstan, pint",
name
)
})?,
None => auto_detect_filter(&buf),
};
let output = apply_filter(filter_fn, &buf);View on GitHub (pinned to d977e1c316)
Solutions
- Switch to byte-safe passthrough: `gzip -dc app.log.gz | rtk pipe --passthrough` (io::copy, no UTF-8 requirement, no cap)
- Convert to text before filtering: `gzip -dc app.log.gz | strings | rtk pipe`, or `iconv -f latin1 -t utf8 logs.txt | rtk pipe`
- Pre-verify the stream: `iconv -f utf-8 -t utf-8 < input > /dev/null` exits non-zero on invalid UTF-8
Example fix
# before: binary stream -> "Failed to read stdin: stream did not contain valid UTF-8" gzip -dc app.log.gz | rtk pipe # after gzip -dc app.log.gz | rtk pipe --passthrough # byte-for-byte, no UTF-8 need gzip -dc app.log.gz | zcat -f | strings | rtk pipe # or make it textual first
Defensive patterns
Strategy: validation
Validate before calling
bash:
# verify the stream is UTF-8 before handing it to rtk pipe
iconv -f utf-8 -t utf-8 < input > /dev/null 2>&1 || { echo "not UTF-8 — use rtk pipe --passthrough" >&2; exit 2; }
rtk pipe --filter cargo-test < input Type guard
rust:
fn stdin_is_utf8(buf: &[u8]) -> bool {
std::str::from_utf8(buf).is_ok()
} Try / catch
rust:
match pipe_cmd::run(filter_name, false) {
Err(e) if e.to_string().contains("stream did not contain valid UTF-8")
|| e.to_string().contains("Failed to read stdin") => {
// binary input: redo as byte-safe passthrough, no UTF-8 requirement
pipe_cmd::run(None, true)
}
r => r,
} Prevention
- Decompress before filtering: pipe gunzipped text, never raw .gz bytes
- Route binary or unknown-encoding streams to `rtk pipe --passthrough`
- Normalize legacy encodings (latin-1, UTF-16) with iconv upstream
- Remember the cap check happens after the UTF-8 read — fix encoding first when debugging
When it happens
Trigger: Piping non-UTF-8 bytes into `rtk pipe` or `rtk pipe --filter <name>`: `gzip -dc app.log.gz | rtk pipe` (compressed bytes), tar streams, images/binaries, latin-1 or UTF-16 logs; also a stdin fd that returns an error (closed or bad descriptor).
Common situations: Forgetting that .gz/.zst output is binary until decompressed; Windows-origin logs in UTF-16; locale-mojibake build logs with stray 0x80-0xFF bytes; piping `cat` of a .node/.wasm asset.
Related errors
- Failed to relay stdin: {}
- stdin exceeds {} byte limit
- Unknown filter '{}'. Available: cargo-test, pytest, go-test,
- hook stdin exceeds {} byte limit
AI-assisted analysis of rtk-ai/rtk@d977e1c316 (2026-08-16).
Data as JSON: /api/errors/229f9a4cee75fd30.
Report an issue: GitHub.