rust-bakery/nom · error
Cannot call `finish()` on `Err(Err::Incomplete(_))`: this…
Error message
Cannot call `finish()` on `Err(Err::Incomplete(_))`: this result means that the parser does not have enough data to decide, you should gather more data and try to reapply the parser instead
What it means
nom's `Finish::finish()` converts an `IResult` into a plain `Result`, but it can only do so when the parser produced a definitive `Error` or `Failure`. If the parser returned `Err::Incomplete(Needed)`, the outcome is genuinely undecided — the parser simply lacks enough input bytes to decide — so `finish()` panics rather than fabricate a wrong answer. This is a misuse-of-API panic: streaming/incomplete results must be handled by feeding more data and re-running the parser.
Solutions
- Don't call `finish()` when the input can be incomplete: match on the `IResult` yourself and handle `Err::Incomplete(Needed)` by reading more data and reapplying the parser.
- Ensure the input buffer is fully populated before parsing: loop on `read()` (or use `BufReader`/`read_exact`) until `input.len()` satisfies the parser, then call `finish()`.
- If the whole input is expected to be final (not a stream), switch streaming parsers to their `complete` equivalents (`nom::bytes::complete::*`) so they return `Err::Error` instead of `Err::Incomplete` on short input.
- If a panic is acceptable but a message is wanted, pre-check with `matches!(result, Err(Err::Incomplete(_)))` before calling `finish()`.
Example fix
// before
let (rest, parsed) = my_parser(&buf).finish()?; // panics on Err::Incomplete
// after
match my_parser(&buf) {
Ok((rest, parsed)) => { /* continue */ }
Err(nom::Err::Incomplete(nom::Needed::new(min))) => {
buf.reserve(min);
// read more bytes from the source and retry the parser
}
Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => return Err(e),
} Defensive patterns
Strategy: validation
Validate before calling
fn is_incomplete<I, O, E>(res: &nom::IResult<I, O, E>) -> bool {
matches!(res, Err(nom::Err::Incomplete(_)))
}
// call .finish() only when !is_incomplete(&parsed) Type guard
fn finishable<I, O, E>(res: &nom::IResult<I, O, E>) -> bool {
!matches!(res, Err(nom::Err::Incomplete(_)))
} Try / catch
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(||
my_parser(&buf).finish()
)).map_err(|_| ParseError::IncompleteInput); Prevention
- Match on IResult directly instead of calling finish() whenever input can arrive incrementally.
- Loop reads until the parser stops returning Err::Incomplete; keep the buffer and reapply the parser.
- Prefer complete combinators (nom::bytes::complete) for non-streaming, fully-buffered input.
- Reserve buffer capacity using the Needed value returned in Err::Incomplete.
- Add a debug assertion or pre-check for Err::Incomplete in tests covering truncated inputs.
When it happens
Trigger: Calling `.finish()` on the result of a parser run against input that is too short for the parser to decide — e.g. `my_parser(input).finish()` where `my_parser` internally uses `length_bytes`/`take`/`count`/streaming combinators and `input.len()` is less than the declared length, or any `nom::bytes::streaming`/`nom::character::complete`-style parser returning `Err::Incomplete`.
Common situations: 1) Parsing a length-prefixed chunk (e.g. `length_data(be_u32)`) where the buffer was truncated by a socket read or partial file read. 2) Migrating code from nom 5/6 streaming parsers to nom 7 `complete` parsers while still calling `finish()` on results that can be `Incomplete`. 3) Reading a frame from a network stream with a single small `read()` call instead of looping until enough bytes accumulate. 4) Feeding an empty or one-byte slice to a parser that requires a header.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
AI-assisted analysis of rust-bakery/nom@51c3c4e44f (2026-09-09).
Data as JSON: /api/errors/8e73f8dd8e28df2b.
Report an issue: GitHub.
Appendix: source
Thrown at src/internal.rs:42
/// management libraries. It keeps the same `Ok` branch, and merges `Err::Error`
/// and `Err::Failure` into the `Err` side.
///
/// *warning*: if the result is `Err(Err::Incomplete(_))`, this method will panic.
/// - "complete" parsers: It will not be an issue, `Incomplete` is never used
/// - "streaming" parsers: `Incomplete` will be returned if there's not enough data
/// for the parser to decide, and you should gather more data before parsing again.
/// Once the parser returns either `Ok(_)`, `Err(Err::Error(_))` or `Err(Err::Failure(_))`,
/// you can get out of the parsing loop and call `finish()` on the parser's result
fn finish(self) -> Result<(I, O), E>;
}
impl<I, O, E> Finish<I, O, E> for IResult<I, O, E> {
fn finish(self) -> Result<(I, O), E> {
match self {
Ok(res) => Ok(res),
Err(Err::Error(e)) | Err(Err::Failure(e)) => Err(e),
Err(Err::Incomplete(_)) => {
panic!("Cannot call `finish()` on `Err(Err::Incomplete(_))`: this result means that the parser does not have enough data to decide, you should gather more data and try to reapply the parser instead")
}
}
}
}
/// Contains information on needed data if a parser returned `Incomplete`
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Needed {
/// Needs more data, but we do not know how much
Unknown,
/// Contains the required data size in bytes
Size(NonZeroUsize),
}
impl Needed {
/// Creates `Needed` instance, returns `Needed::Unknown` if the argument is zero
pub fn new(s: usize) -> Self {
match NonZeroUsize::new(s) {View on GitHub (pinned to 51c3c4e44f)