{"record":{"id":"20208fcb7f76020a","repo":"PRQL/prql","slug":"unexpected-found-display-at-position-char-start","errorCode":null,"errorMessage":"Unexpected {found_display} at position {char_start}..{char_end}","messagePattern":"Unexpected (.+?) at position (.+?)\\.\\.(.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"prqlc/prqlc-parser/src/lexer/mod.rs","lineNumber":52,"sourceCode":"        .skip(char_start)\n        .take(char_end - char_start)\n        .collect();\n\n    // If found is empty, report as \"end of input\", otherwise wrap in quotes\n    let found_display = if found.is_empty() {\n        \"end of input\".to_string()\n    } else {\n        format!(\"'{}'\", found)\n    };\n\n    // Create a new Error with the extracted information\n    let error_source = format!(\n        \"Unexpected {} at position {}..{}\",\n        found_display, char_start, char_end\n    );\n\n    WithErrorInfo::with_span(\n        Error::new(Reason::Unexpected {\n            found: found_display,\n        }),\n        Some(crate::span::Span {\n            start: char_start,\n            end: char_end,\n            source_id,\n        }),\n    )\n    .with_source(ErrorSource::Lexer(error_source))\n}\n\n/// Lex PRQL into LR, returning the tokens if the whole source lexed and the\n/// errors if it didn't. The lexer doesn't resume after an error, so tokens and\n/// errors never come back together.\npub fn lex_source_recovery(source: &str, source_id: u16) -> (Option<Vec<Token>>, Vec<E>) {\n    let result = lexer().parse(source).into_result();\n\n    match result {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/PRQL/prql/blob/e164e249b99485890036eb60f57c37520379b240/prqlc/prqlc-parser/src/lexer/mod.rs#L34-L70","documentation":"The PRQL lexer produces `Reason::Unexpected` when a character cannot start any valid token at a given position. The message reports the found text and the character range, wrapped with span info so the CLI can render a source-annotated diagnostic.","triggerScenarios":"Any lexically invalid input: stray characters (e.g. `#` isn't a comment? actually `#` in wrong place), unterminated strings/quotes, unmatched brackets, or control characters inside a query fed to `prqlc compile` or the parser API.","commonSituations":"Copy-pasted SQL syntax into PRQL (e.g. `*` from `SELECT *` misuse), smart quotes from word processors, non-ASCII characters in identifiers, accidental keyboard input.","solutions":["Look at the reported position range and fix or remove the unexpected character","Replace SQL-isms with PRQL equivalents (e.g. `derive`, `select` instead of `SELECT *`)","Check for invisible/smart-quote characters after pasting"],"exampleFix":"// before\nfrom employees | filter salary > 100k?\n// after\nfrom employees | filter salary > 100000","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try { compile(prql) } catch (e) { if (e.reason === 'Unexpected') { showAtSpan(e.span, e.found) } else { throw e } }","preventionTips":["Sanitize pasted text: replace smart quotes, strip BOM/control chars","Write PRQL syntax, not SQL fragments","Run queries through prqlc fmt to catch stray characters early"],"tags":["lexer","syntax-error","parsing"],"backgroundTag":"invalid-argument-format","analyzedSha":"e164e249b99485890036eb60f57c37520379b240","analyzedAt":"2026-09-09T12:18:38.727Z","contentChangedAt":"2026-09-09T12:18:38.727Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}