[hero_agent][P1] UTF-8 byte-slice panic in agent.rs:853 — crashes mid-stream on tool results containing multi-byte chars #17
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_agent#17
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
hero_agentpanics withbyte index N is not a char boundarywhen a tool result (most oftenfile_read) contains multi-byte UTF-8 characters and a downstream byte-offset slice lands mid-codepoint. Observed live on herodemo VM 2026-05-01 during a "who are my contacts" agent flow; the agent crashed silently mid-stream and the UI surfaced as"No response received from AI".The crash kills the response stream while the UI still believes the request is in flight, so the user sees a blank/aborted answer with no error context.
Stack trace (live capture)
The
─is a 3-byte UTF-8 sequence (0xE2 0x94 0x80); slicing at byte 500 lands inside it. The source string is the rendered output offile_readon a Rust source file with line-prefix box-drawing characters.Reproduction (live, 2026-05-01)
who are the persons/contacts in my hero biz crm tool?search_hero_docs,shell_run,file_read, …file_readreturns content containing─(typical in Rust doc-comment headers).agent.rs:853:50while preparing the tool result for the next LLM turn."No response received from AI".The crash is not deterministic per query — shorter tool flows that don't read box-drawing-laden files complete normally. A retry of the same query a few minutes later succeeded (different tool-iteration path, didn't hit a
─).Root cause (likely)
agent.rs:853:50is doing&s[..N](or equivalent) whereNis computed assuming byte = char. Common patterns that trip this:The fix is one of:
s.char_indices()to find a safe slice boundary.s.chars().take(N).collect::<String>()for a char-count cap (slower, allocates).unicode-truncate.A simple
floor_char_boundary(N)(stable since Rust 1.80) would also do, walking back from N until landing on a char boundary.Blast radius
This bites any tool flow whose results contain non-ASCII UTF-8 — which is most of them on this codebase: every
file_readof Rust sources with///doc tables, every README that has em-dashes (—), every nu module with box-drawing inprintheaders. So most multi-iteration agent queries are at risk; only single-shot queries that don't read source files are safe.The crash also burns the conversation: the OSIS-store calls afterward (audit entry, usage entry) fail with 404 because the runtime aborted mid-handler. The downstream WARN spam in agent logs (
Failed to create usage entry,Failed to list memories) is a symptom of this same crash, not an independent bug.Suggested fix (minimal)
In
hero_agent/crates/hero_agent/src/agent.rs:853(and a sweep of other byte-slice sites in the same file):Plus a regression test:
Related
tool_choice = Specific("search_hero_docs")at iteration 0, per docs_hero/collections/hero_os_guide/service_agent.md) reduces the iteration count and therefore the probability of hitting a─. Doesn't fix the bug, but reduces exposure.hero_agent/crates/hero_agent_server/src/routes.rsalready swallows the OSIS-store 404s — those are downstream of this crash, not the trigger.Severity
P1 for demo-visible behaviour (agent silent fail on common queries); P2 by code-quality classification (single-line UTF-8 slicing bug, stable Rust API available).
Signed-off-by: mik-tf
mik-tf referenced this issue from lhumina_code/hero_demo2026-05-02 03:28:52 +00:00