{"record":{"id":"8e73f8dd8e28df2b","repo":"rust-bakery/nom","slug":"cannot-call-finish-on-err-err-incomplete","errorCode":null,"errorMessage":"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","messagePattern":"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","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/internal.rs","lineNumber":42,"sourceCode":"  /// management libraries. It keeps the same `Ok` branch, and merges `Err::Error`\n  /// and `Err::Failure` into the `Err` side.\n  ///\n  /// *warning*: if the result is `Err(Err::Incomplete(_))`, this method will panic.\n  /// - \"complete\" parsers: It will not be an issue, `Incomplete` is never used\n  /// - \"streaming\" parsers: `Incomplete` will be returned if there's not enough data\n  ///   for the parser to decide, and you should gather more data before parsing again.\n  ///   Once the parser returns either `Ok(_)`, `Err(Err::Error(_))` or `Err(Err::Failure(_))`,\n  ///   you can get out of the parsing loop and call `finish()` on the parser's result\n  fn finish(self) -> Result<(I, O), E>;\n}\n\nimpl<I, O, E> Finish<I, O, E> for IResult<I, O, E> {\n  fn finish(self) -> Result<(I, O), E> {\n    match self {\n      Ok(res) => Ok(res),\n      Err(Err::Error(e)) | Err(Err::Failure(e)) => Err(e),\n      Err(Err::Incomplete(_)) => {\n        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\")\n      }\n    }\n  }\n}\n\n/// Contains information on needed data if a parser returned `Incomplete`\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum Needed {\n  /// Needs more data, but we do not know how much\n  Unknown,\n  /// Contains the required data size in bytes\n  Size(NonZeroUsize),\n}\n\nimpl Needed {\n  /// Creates `Needed` instance, returns `Needed::Unknown` if the argument is zero\n  pub fn new(s: usize) -> Self {\n    match NonZeroUsize::new(s) {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/rust-bakery/nom/blob/51c3c4e44fa78a8a09b413419372b97b2cc2a787/src/internal.rs#L24-L60","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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()`."],"exampleFix":"// before\nlet (rest, parsed) = my_parser(&buf).finish()?; // panics on Err::Incomplete\n\n// after\nmatch my_parser(&buf) {\n  Ok((rest, parsed)) => { /* continue */ }\n  Err(nom::Err::Incomplete(nom::Needed::new(min))) => {\n    buf.reserve(min);\n    // read more bytes from the source and retry the parser\n  }\n  Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => return Err(e),\n}","handlingStrategy":"validation","validationCode":"fn is_incomplete<I, O, E>(res: &nom::IResult<I, O, E>) -> bool {\n    matches!(res, Err(nom::Err::Incomplete(_)))\n}\n// call .finish() only when !is_incomplete(&parsed)","typeGuard":"fn finishable<I, O, E>(res: &nom::IResult<I, O, E>) -> bool {\n    !matches!(res, Err(nom::Err::Incomplete(_)))\n}","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(||\n    my_parser(&buf).finish()\n)).map_err(|_| ParseError::IncompleteInput);","preventionTips":["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."],"tags":["nom","parser","incomplete-input","panic","streaming"],"backgroundTag":"internal-invariant-violation","analyzedSha":"51c3c4e44fa78a8a09b413419372b97b2cc2a787","analyzedAt":"2026-09-09T16:04:56.502Z","contentChangedAt":"2026-09-09T16:04:56.502Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}