xai-org/grok-build · warning
just created
Error message
just created
What it means
`ensure_mermaid_runtime` lazily creates the `MermaidRuntime` and then unwraps `self.mermaid.as_mut().expect("just created")`. The expect is an internal invariant: the Option was set two lines earlier, so this can only panic if re-entrant mutable access or a panic mid-initialization left the state inconsistent — practically it should be unreachable.
Source
Thrown at crates/codegen/xai-grok-pager/src/app/mermaid_worker.rs:918
}
/// Representative content columns for diagram render sizing this frame.
fn mermaid_content_cols(&self) -> u16 {
representative_content_cols(self.last_terminal_size.0)
}
/// Drive the lazy mermaid work for one tick: poll the worker for finished on-click renders and run each requesting action.
/// Returns `true` when a redraw is warranted. A no-op until a click is in flight.
pub fn mermaid_tick(&mut self) -> bool {
self.poll_mermaid_results()
}
/// Lazily create the render runtime (and spawn the worker) on first need.
fn ensure_mermaid_runtime(&mut self) -> &mut MermaidRuntime {
if self.mermaid.is_none() {
self.mermaid = Some(MermaidRuntime::new());
}
self.mermaid.as_mut().expect("just created")
}
/// Per-session destination path for a diagram's PNG, or `None` until session identity is known (no on-disk cache before then).
fn mermaid_out_path(&self, key: &MermaidCacheKey) -> Option<PathBuf> {
// Test override: a hermetic per-test cache dir (no `GROK_HOME` mutation)
#[cfg(test)]
if let Some(path) = TEST_MERMAID_DIR.with(|d| {
d.borrow()
.as_ref()
.map(|tmp| tmp.path().join(key.cache_filename()))
}) {
return Some(path);
}
let dir = crate::prompt_images::session_mermaid_dir(
self.session.session_id.as_ref(),
&self.session.cwd,
)?;
Some(dir.join(key.cache_filename()))View on GitHub (pinned to bc7f02eddd)
Solutions
- Confirm `MermaidRuntime::new()` doesn't panic (it spawns the worker — check error 745 conditions).
- Inspect recent refactors of `ensure_mermaid_runtime` to ensure the Some(...) assignment still precedes the expect.
- Rewrite to a single expression avoiding the intermediate expect: `self.mermaid.get_or_insert_with(MermaidRuntime::new)`.
- If it fires, treat it as a logic bug — add a debug_assert/log capturing how the field was None after assignment.
Example fix
// before
if self.mermaid.is_none() {
self.mermaid = Some(MermaidRuntime::new());
}
self.mermaid.as_mut().expect("just created")
// after
self.mermaid.get_or_insert_with(MermaidRuntime::new) Defensive patterns
Strategy: type-guard
Validate before calling
// collapse the lazy-init so no expect is needed let rt = self.mermaid.get_or_insert_with(MermaidRuntime::new);
Type guard
fn runtime_ready(rt: &Option<MermaidRuntime>) -> bool {
rt.is_some()
} Try / catch
// not applicable: invariant panic; use get_or_insert_with to remove it let rt = self.mermaid.get_or_insert_with(MermaidRuntime::new);
Prevention
- Prefer Option::get_or_insert_with over set-then-expect lazy init
- Review refactors touching this method for removed Some(...) assignment
- Add a unit test exercising first-render to keep the lazy path covered
When it happens
Trigger: Only reachable if `MermaidRuntime::new()` panics (leaving the field never stored) or if the borrow/invariant around `&mut self` is violated by refactoring; normal call flow (first mermaid render request via `request_mermaid_render`) cannot trigger it.
Common situations: A refactor that moved or removed the `self.mermaid = Some(...)` assignment; `MermaidRuntime::new()` panicking during asset/worker initialization (see error 745's thread spawn); concurrent access bugs surfaced by unsafe code changes.
Related errors
- spawn mermaid-render thread
- set on the use_leader path
- a successful full-replace sample stashes its CompactOutput
- Task panicked: {}
- send_with_retry_escaping_pool ran at least one attempt
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/203cbdca047e544c.
Report an issue: GitHub.