vllm-project/vllm · error · UnifiedParserError
combined parser is constructed from split parser instances
Error message
combined parser is constructed from split parser instances
What it means
UnifiedParserError::CombinedParserConstructor is an API-misuse guard: a combined (unified) parser must be constructed through its own constructor that takes the tokenizer and shared configuration, not assembled from already-built split reasoning/tool parser instances. Building it from split instances would leave token IDs and delimiter state inconsistent, so the constructor rejects that path.
Source
Thrown at rust/src/parser/src/unified/mod.rs:204
/// Feed one decoded text delta into the parser, appending committed output into `output`.
fn parse_into(&mut self, delta: &str, output: &mut UnifiedParserOutput) -> Result<()>;
/// Flush any buffered parser state at end of stream.
fn finish(&mut self) -> Result<UnifiedParserOutput> {
Ok(UnifiedParserOutput::default())
}
/// Clear parser state and return currently uncommitted buffered text.
fn reset(&mut self) -> String {
String::new()
}
}
/// Errors produced while creating or running unified parsers.
#[derive(Debug, Error, Macro)]
#[thiserror_ext(macro(path = "crate::unified", mangle))]
pub enum UnifiedParserError {
#[error("combined parser is constructed from split parser instances")]
CombinedParserConstructor,
#[error("tokenizer is missing unified parser token `{token}`")]
MissingToken { token: String },
#[error("unified parser parsing failed: {message}")]
ParsingFailed { message: String },
#[error(transparent)]
Reasoning(#[from] ReasoningError),
#[error(transparent)]
Tool(#[from] ToolParserError),
}
/// Returns the ID for the given token, or an error if it's not found.
fn token_id(tokenizer: &dyn vllm_tokenizer::Tokenizer, token: &str) -> Result<u32> {
tokenizer.token_to_id(token).ok_or_else(|| UnifiedParserError::MissingToken {
token: token.to_string(),
})
}
View on GitHub (pinned to c794754062)
Solutions
- Construct the unified parser via its dedicated constructor taking tokenizer + names/config, not parser instances
- If you already have split parsers, keep using the split (non-unified) pipeline instead of combining them
Example fix
// before
let p = CombinedParser::from_split(reasoning_parser, tool_parser);
// after
let p = CombinedParser::new(&tokenizer, UnifiedParserConfig::new("granite")); Defensive patterns
Strategy: type-guard
Validate before calling
// Prevent constructing the combined parser from split instances
fn wants_unified(cfg: &ParserConfig) -> bool { cfg.reasoning == cfg.tool && !cfg.reasoning.is_empty() }
if wants_unified(&cfg) { build_unified(&cfg).await } else { build_split(&cfg).await } Type guard
fn is_combined_ctor_misuse(e: &UnifiedParserError) -> bool {
matches!(e, UnifiedParserError::CombinedParserConstructor)
} Try / catch
match CombinedParser::new(args) {
Err(e @ UnifiedParserError::CombinedParserConstructor) => {
return Err(anyhow::anyhow!("use the unified constructor with tokenizer + config, not split instances: {e}"));
}
r => r?,
} Prevention
- Use the dedicated unified constructor (tokenizer + family/config) and delete from_split-style call sites
- If you already hold split parsers, run them as a split pipeline instead
- Add a compile-time doc note and runtime guard on any constructor taking trait objects
When it happens
Trigger: Calling the combined-parser constructor with arguments that resolve to split parser instances (e.g. passing pre-built ReasoningParser/ToolParser trait objects) instead of letting it construct the unified components itself.
Common situations: Library users refactoring from split parsers to the unified API and passing their old parser objects; generic code that funnels any parser pair into the combined constructor.
Related errors
- tool response messages require a tool_call_id; use ChatMessa
- request `{request_id}` is already in flight
- engine-core client is closed: {message}
- generate request `{request_id}` has an empty prompt_token_id
- `{name}` only provides a unified parser; the same reasoning
AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14).
Data as JSON: /api/errors/8657683926625d47.
Report an issue: GitHub.