Troubleshooting Guide
Common issues when working with the Glaucus YAML library, organized by symptom.
Parse Failures
"unexpected token" on valid YAML
Symptom: ErrorKind::UnexpectedToken on input that other parsers accept.
Common causes:
- Indentation mismatch — Glaucus is strict about indentation. Mixed tabs and spaces will fail.
- Duplicate keys — Glaucus defaults to
Strictness::Strict, which rejects duplicate keys. UseStrictness::Lenientto allow them. - Document boundary — Content after
...requires---to start a new document (YAML 9.2).
Diagnosis:
// Isolate to scanner level
let mut scanner = glaucus_core::scanner::Scanner::new(input);
while let Some(result) = scanner.next_token() {
match result {
Ok(token) => println!("{:?}", token),
Err(e) => { println!("Scanner error: {e}"); break; }
}
}"depth exceeded" or "node count exceeded"
Symptom: ErrorKind::LimitExceeded on deeply nested or large documents.
Fix: Increase ResourceLimits for trusted input:
use glaucus_core::error::ParserConfig;
use glaucus_core::limits::ResourceLimits;
let config = ParserConfig {
limits: ResourceLimits {
// Capped at MAX_SAFE_DEPTH (192) however high this is set -- see below.
max_depth: 192, // default: 128
max_node_count: 10_000_000, // default: 1_000_000
max_total_alias_nodes: 500_000, // default: 100_000
max_scalar_length: 64 << 20, // default: 10 MiB
..ResourceLimits::default()
},
..ParserConfig::default()
};
max_depthis clamped and cannot be raised past 192. Composition is recursive, so a document deep enough to pass a raised limit would overflow the stack and abort — uncatchable, taking the process with it. The effective limit ismin(max_depth, MAX_SAFE_DEPTH), so setting it higher (or callingResourceLimits::unlimited()) gives you a cleanDepthLimitExceededinstead. If you need genuinely deeper documents, say so on #33 — lifting the ceiling means making composition iterative.
Block scalar content is wrong
Symptom: Literal (|) or folded (>) scalars have missing or extra newlines.
Check:
- Chomping indicator:
|(clip, default),|-(strip trailing),|+(keep trailing) - Indentation indicator:
|2forces 2-space indent detection - EOF handling: Glaucus treats EOF as an implicit line break (YAML spec)
Anchor/alias not resolving
Symptom: Alias *name fails with "undefined alias" error.
Check:
- Anchors are per-document — they reset at
---boundaries. - Forward references are not supported (anchor must appear before alias).
- Two separate alias limits apply, and they count different things:
max_alias_expansions(default: 1,024) counts how many times an alias appears, whilemax_total_alias_nodes(default: 100,000) counts the nodes those appearances actually materialise. A billion-laughs document keeps the first tiny while inflating the second, so it is the second that rejects it.
Wrong Output
Emitter produces different YAML than input
Expected behavior. Glaucus normalizes output:
- Indentation is standardized to
EmitterConfig.indent(default: 2) - Flow collections may be expanded to block style
- Comments are not preserved (YAML spec does not require comment preservation)
- Quoted strings may change style based on content
For round-trip fidelity, use the Node API which preserves ScalarStyle.
Serde serialization adds unexpected quotes
Cause: The serializer's needs_quoting() function in ser.rs decides when to quote. A value is quoted if it looks like a YAML special value (true, false, null, numbers) or contains characters that require quoting (:, #, [, {, etc.).
This is correct behavior — it ensures the output is valid YAML that parses back to the same type.
Performance Issues
Benchmarks show regression
Diagnosis:
# Run benchmarks and compare
cargo bench -p glaucus-bench
# Check specific stage
cargo bench -p glaucus-bench --bench scanner
cargo bench -p glaucus-bench --bench parser
cargo bench -p glaucus-bench --bench composer
cargo bench -p glaucus-bench --bench emitterCommon causes:
- Extra allocations —
String::new()or.to_owned()added to hot paths - Algorithm change — O(n) operation replaced with O(n^2)
- Lost zero-copy —
Cow::Borrowedreplaced withCow::Owned
Large documents are disproportionately slow
Check for O(n^2) patterns:
- Token buffer scans —
VecDequeoperations should be O(1) - Simple key search — should not scan the entire key list
- Node tree construction — pre-allocate
Veccapacity when possible
Test Suite Failures
YAML test suite test XXXX fails
Diagnosis:
# Read the test data
ls glaucus-yaml-test-suite/data/XXXX/
# Files:
# in.yaml — input
# test.event — expected event sequence (optional)
# in.json — expected JSON output (optional)
# error — if present, input should fail to parseCommon edge cases by category:
| Test IDs | Category | Known Difficulty |
|---|---|---|
| DK4H, ZXT5 | Flow sequence implicit keys | Single-line constraint |
| 5LLU, S98Z, W9L4 | Block scalar indentation | Over-indented whitespace lines |
| 9KBC, CXX2 | Document start line | Collections on --- line |
| G9HC, H7J7 | Node property indentation | Properties at n+1 |
| BS4K, KS4U | Bare document after implicit end | Only --- starts new doc |
| JEF9/02 | Block scalar EOF | Implicit line break at EOF |
| MUS6/03 | YAML directive whitespace | Tab after %YAML |
Build Issues
cargo deny check fails with "multiple versions"
Cause: A new dependency pulled in a second version of an existing crate.
Fix: Check which dependency introduced the duplicate:
cargo tree --duplicatesThen either pin versions or add a skip entry to deny.toml (last resort).
Clippy warnings after dependency update
Cause: New Clippy version introduced stricter lints.
Fix: Address warnings directly. If a lint is inappropriate for this codebase, add it to clippy.toml or #[allow()] with a comment explaining why.