rust-lang/cargo · error
failed to parse process output: {}
Error message
failed to parse process output: {} What it means
From ProcessBuilder::exec_with_streaming (crates/cargo-util/src/process_builder.rs:346-451). For each stdout/stderr line it calls the on_stdout_line / on_stderr_line callback; the first Err is stashed in callback_error. After the child exits, if callback_error is set it bails wrapping the original error with a ProcessError whose message is `failed to parse process output: {self}`. It means the process ran but its line-by-line output could not be interpreted by the supplied callback.
Source
Thrown at crates/cargo-util/src/process_builder.rs:440
}
status
})()
.with_context(|| ProcessError::could_not_execute(self))?;
let output = Output {
status,
stdout,
stderr,
};
{
let to_print = if capture_output { Some(&output) } else { None };
if let Some(e) = callback_error {
let cx = ProcessError::new(
&format!("failed to parse process output: {}", self),
Some(output.status),
to_print,
);
bail!(anyhow::Error::new(cx).context(e));
} else if !output.status.success() {
bail!(ProcessError::new(
&format!("process didn't exit successfully: {}", self),
Some(output.status),
to_print,
));
}
}
Ok(output)
}
/// Builds the command with an `@<path>` argfile that contains all the
/// arguments. This is primarily served for rustc/rustdoc command family.
fn build_command_with_argfile(&self) -> io::Result<(Command, NamedTempFile)> {
use std::io::Write as _;
let mut tmp = tempfile::Builder::new()View on GitHub (pinned to 0e07a15537)
Solutions
- Use matching rustc and Cargo versions from the same toolchain (rustup manages this).
- Remove output-mangling wrappers (sccache/ccache/proxies) from the failing command to isolate the cause.
- Re-run; transient truncation (OOM kill, pipe close) can produce malformed final lines.
- If you supply the callback yourself, make it tolerant: skip/log unparseable lines instead of returning Err.
Example fix
// before: callback hard-fails on any non-json line
let out = p.exec_with_streaming(
&mut |l| { serde_json::from_str::<Msg>(l)?; Ok(()) },
&mut |_| Ok(()),
true,
)?;
// after: skip lines that aren't valid json
let out = p.exec_with_streaming(
&mut |l| {
if serde_json::from_str::<Msg>(l).is_err() {
log::warn!("ignoring non-json line: {l}");
}
Ok(())
},
&mut |_| Ok(()),
true,
)?; Defensive patterns
Strategy: try-catch
Try / catch
// Distinguish callback-parse failures from process-exit failures
use cargo_util::{ProcessError, ProcessBuilder};
match p.exec_with_streaming(&mut cb_out, &mut cb_err, true) {
Ok(out) => out,
Err(e) => {
let is_parse = e.downcast_ref::<ProcessError>()
.map(|pe| pe.to_string().contains("failed to parse process output"))
.unwrap_or(false);
if is_parse {
log::warn!("tool output parse failed; falling back to non-streaming");
p.exec()? // retry without streaming callbacks
} else {
return Err(e);
}
}
} Prevention
- Keep rustc and Cargo from the same toolchain to avoid JSON schema skew.
- Make streaming callbacks tolerant: log/skip unparseable lines instead of returning Err.
- Avoid wrapping build commands in proxies that interleave stdout.
When it happens
Trigger: Cargo spawns rustc/rustdoc with --error-format=json (or a message-format=json callback) and a callback that serde-parses each line fails on a malformed line. A build script or wrapper emitting non-JSON into a JSON-expecting stream. Output truncated mid-line by a proxy.
Common situations: Version skew: a newer rustc emits JSON fields the older Cargo callback rejects. sccache/ccache/distcc or an IDE proxy interleaving or corrupting stdout. A build script printing stray text to stdout that Cargo tries to parse as build directives.
Related errors
- path at `{}` was not valid utf-8
- no executable for `{}` found in PATH
- jobs may not be 0
- could not parse `{j}`. Number of parallel jobs should be `de
- malformed output when learning about crate-type {} informati
AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06).
Data as JSON: /data/errors/d122257b12b05a5c.json.
Report an issue: GitHub.