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

  1. 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.
  2. 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()`.
  3. 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.
  4. 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

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)