Skip to main content

stet_pdf_reader/
error.rs

1// stet-pdf-reader
2// Copyright (c) 2026 Scott Bowman
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! PDF parsing error types.
6
7use thiserror::Error;
8
9/// Errors that can occur during PDF parsing and object resolution.
10///
11/// Marked `#[non_exhaustive]` so new error variants can land additively;
12/// downstream consumers must include a wildcard arm in `match` sites.
13#[derive(Debug, Error)]
14#[non_exhaustive]
15pub enum PdfError {
16    #[error("not a PDF file (missing %PDF header)")]
17    NotAPdf,
18
19    #[error("unsupported PDF version: {0}")]
20    UnsupportedVersion(String),
21
22    #[error("startxref not found")]
23    NoStartXref,
24
25    #[error("malformed xref table at offset {0}")]
26    MalformedXref(usize),
27
28    #[error("malformed trailer dictionary")]
29    MalformedTrailer,
30
31    #[error("object {obj_num} {gen_num} not found")]
32    ObjectNotFound { obj_num: u32, gen_num: u16 },
33
34    #[error("unexpected token: expected {expected}, got {got}")]
35    UnexpectedToken { expected: String, got: String },
36
37    #[error("unterminated {0}")]
38    Unterminated(&'static str),
39
40    #[error("invalid object at offset {0}")]
41    InvalidObject(usize),
42
43    #[error("stream missing /Length")]
44    StreamMissingLength,
45
46    #[error("unsupported filter: {0}")]
47    UnsupportedFilter(String),
48
49    #[error("decompression error: {0}")]
50    DecompressionError(String),
51
52    #[error("missing required key /{0} in dictionary")]
53    MissingKey(&'static str),
54
55    #[error("type mismatch: expected {expected} for /{key}")]
56    TypeMismatch { key: String, expected: &'static str },
57
58    #[error("page index {0} out of range (document has {1} pages)")]
59    PageOutOfRange(usize, usize),
60
61    #[error("circular reference detected for object {0} {1}")]
62    CircularReference(u32, u16),
63
64    /// A recursive-descent parse hit its nesting cap.
65    ///
66    /// Raised instead of letting a crafted file exhaust the native stack,
67    /// which aborts the process rather than unwinding.
68    #[error("{context} nesting exceeded the limit of {limit}")]
69    NestingTooDeep {
70        /// What was being parsed, e.g. `"array/dictionary"`.
71        context: &'static str,
72        /// The cap that was reached.
73        limit: u32,
74    },
75
76    #[error("PDF requires a password")]
77    PasswordRequired,
78
79    #[error("{0}")]
80    Other(String),
81}