Skip to main content

libgraphql_parser/
graphql_parse_error_kind.rs

1use crate::DefinitionKind;
2use crate::DocumentKind;
3use crate::ReservedNameContext;
4use crate::ValueParsingError;
5
6/// Categorizes parse errors for programmatic handling.
7///
8/// Each variant contains minimal data needed for programmatic decisions.
9/// Human-readable context (suggestions, explanations) belongs in the
10/// `notes` field of `GraphQLParseError`.
11///
12/// The `#[error(...)]` messages are concise/programmatic. Full human-readable
13/// messages are in `GraphQLParseError.message`.
14#[derive(Debug, Clone, PartialEq, thiserror::Error)]
15pub enum GraphQLParseErrorKind {
16    /// Expected specific token(s) but found something else.
17    ///
18    /// This is the most common error type — the parser expected certain tokens
19    /// based on grammar rules but encountered something unexpected.
20    ///
21    /// # Example
22    /// ```text
23    /// type User { name String }
24    ///                  ^^^^^^ expected `:`, found `String`
25    /// ```
26    #[error("unexpected token: `{found}`")]
27    UnexpectedToken {
28        /// What tokens were expected (e.g., `[":"​, "{"​, "@"]`).
29        expected: Vec<String>,
30        /// Description of what was found (e.g., `"String"` or `"}"`).
31        found: String,
32    },
33
34    /// Unexpected end of input while parsing.
35    ///
36    /// The document ended before a complete construct was parsed.
37    ///
38    /// # Example
39    /// ```text
40    /// type User {
41    ///           ^ expected `}`, found end of input
42    /// ```
43    #[error("unexpected end of input")]
44    UnexpectedEof {
45        /// What was expected when EOF was encountered.
46        expected: Vec<String>,
47    },
48
49    /// Lexer error encountered during parsing.
50    ///
51    /// The parser encountered a `GraphQLTokenKind::Error` token from the lexer.
52    /// The lexer's error message and notes are preserved in the parent
53    /// `GraphQLParseError`'s `message` and `notes` fields.
54    ///
55    /// # Example
56    /// ```text
57    /// type User { name: "unterminated string
58    ///                   ^ unterminated string literal
59    /// ```
60    #[error("lexer error")]
61    LexerError,
62
63    /// Unclosed delimiter (bracket, brace, or parenthesis).
64    ///
65    /// A delimiter was opened but EOF was reached before finding the matching
66    /// closing delimiter. The opening location is typically included in the
67    /// error's `notes`.
68    ///
69    /// # Example
70    /// ```text
71    /// type User {
72    ///     name: String
73    /// # EOF here — missing `}`
74    /// ```
75    ///
76    /// Note: This is distinct from `MismatchedDelimiter`, which occurs when a
77    /// *wrong* closing delimiter is found (e.g., `[` closed with `)`).
78    #[error("unclosed delimiter: `{delimiter}`")]
79    UnclosedDelimiter {
80        /// The unclosed delimiter (e.g., `"{"`, `"["`, `"("`).
81        delimiter: String,
82    },
83
84    /// Mismatched delimiter.
85    ///
86    /// A closing delimiter was found that doesn't match the most recently
87    /// opened delimiter. This indicates a structural nesting error.
88    ///
89    /// # Example
90    /// ```text
91    /// type User { name: [String) }
92    ///                         ^ expected `]`, found `)`
93    /// ```
94    ///
95    /// Note: This is distinct from `UnclosedDelimiter`, which occurs when EOF
96    /// is reached without any closing delimiter.
97    #[error("mismatched delimiter")]
98    MismatchedDelimiter {
99        /// The expected closing delimiter (e.g., `"]"`).
100        expected: String,
101        /// The actual closing delimiter found (e.g., `")"`).
102        found: String,
103    },
104
105    /// Invalid value (wraps value parsing errors).
106    ///
107    /// Occurs when a literal value (string, int, float) cannot be parsed.
108    ///
109    /// # Example
110    /// ```text
111    /// query { field(limit: 99999999999999999999) }
112    ///                      ^^^^^^^^^^^^^^^^^^^^ integer overflow
113    /// ```
114    #[error("invalid value")]
115    InvalidValue(ValueParsingError),
116
117    /// Reserved name used in a context where it's not allowed.
118    ///
119    /// Certain names have special meaning in specific contexts:
120    /// - `on` cannot be a fragment name (it introduces type conditions)
121    /// - `true`, `false`, `null` cannot be enum values (ambiguous with literals)
122    ///
123    /// # Example
124    /// ```text
125    /// fragment on on User { name }
126    ///          ^^ fragment name cannot be `on`
127    /// ```
128    #[error("reserved name: `{name}`")]
129    ReservedName {
130        /// The reserved name that was used (e.g., `"on"`, `"true"`).
131        name: String,
132        /// The context where this name is not allowed.
133        context: ReservedNameContext,
134    },
135
136    /// Definition kind not allowed in the document being parsed.
137    ///
138    /// When parsing with `parse_executable_document()`, schema definitions
139    /// (types, directives) are not allowed. When parsing with
140    /// `parse_schema_document()`, operations and fragments are not allowed.
141    ///
142    /// # Example
143    /// ```text
144    /// # Parsing as executable document:
145    /// type User { name: String }
146    /// ^^^^ type definition not allowed in executable document
147    /// ```
148    #[error("wrong document kind")]
149    WrongDocumentKind {
150        /// What kind of definition was found.
151        found: DefinitionKind,
152        /// What kind of document is being parsed.
153        document_kind: DocumentKind,
154    },
155
156    /// Empty construct that requires content.
157    ///
158    /// Certain constructs cannot be empty per the GraphQL spec:
159    /// - Selection sets: `{ }` is invalid (must have at least one selection)
160    /// - Argument lists: `()` is invalid (omit parentheses if no arguments)
161    ///
162    /// # Example
163    /// ```text
164    /// query { user { } }
165    ///              ^^^ selection set cannot be empty
166    /// ```
167    #[error("invalid empty construct: `{construct}`")]
168    InvalidEmptyConstruct {
169        /// What construct is empty (e.g., `"selection set"`).
170        construct: String,
171    },
172
173    /// Invalid syntax that doesn't fit other categories.
174    ///
175    /// A catch-all for syntax errors without dedicated variants. The specific
176    /// error is described in `GraphQLParseError.message`.
177    #[error("invalid syntax")]
178    InvalidSyntax,
179}