Skip to content

[Bug] Rust core panics on UTF-8 multi-byte char boundary in sub-agent prompts (v1.5.6) #17

@zoubo9034

Description

@zoubo9034

Bug Description

a3s-code v1.5.6 panics in core/src/agent.rs when a sub-agent prompt contains multi-byte UTF-8 characters (e.g. Chinese). The Rust worker thread attempts a byte-level slice at a fixed offset that lands inside a multi-byte character, violating Rust's UTF-8 char boundary invariant.

This bug appears to have been introduced or exposed in v1.5.6 (was not observed in earlier versions during the same workflow).


Environment

  • a3s-code version: v1.5.6 (Python)
  • Platform: Linux
  • Trigger: Orchestrator.spawn_subagent() with a prompt containing Chinese characters

Panic Output

Two independent worker threads panic with the same error pattern:

thread 'a3s-code-worker' panicked at /home/runner/work/Code/Code/core/src/agent.rs:1301:38:
byte index 180 is not a char boundary; it is inside '析' (bytes 179..182) of
`{"agent":"general","description":"Video analysis with scoring adapter","max_steps":15,
"permissive":true,"prompt":"执行视频分析任务,使用 scoring-video-adapter 技能分析以下视频:\n\n视频路径: /mnt/shared-storage-user/zoubo/workspace/Lo`[...]

thread 'a3s-code-worker' panicked at /home/runner/work/Code/Code/core/src/agent.rs:1301:38:
byte index 180 is not a char boundary; it is inside '器' (bytes 179..182) of
`{"goal":"执行视频评分分析任务。视频路径: /mnt/.../机器9/智能网联2451-...mp4。输出目录: /mnt/shared-s`[...]

Key detail: The panic location is agent.rs:1301 — a hardcoded byte offset of 180 is used to slice a JSON string that contains multi-byte UTF-8 characters. Chinese characters are 3 bytes each in UTF-8, so any fixed byte-offset slice will frequently land mid-character.


Minimal Reproduction

from a3s_code import Agent, Orchestrator, SubAgentConfig

agent = Agent.create("config.hcl")
orch  = Orchestrator.create(agent=agent)

# Any prompt with Chinese characters (multi-byte UTF-8) triggers the panic
handle = orch.spawn_subagent(SubAgentConfig(
    agent_type="general-purpose",
    prompt="请分析这个视频文件,路径为:/path/to/视频文件/机器9/测试.mp4",
    workspace=".",
    permissive=True,
))

try:
    result = handle.wait()
    print(result)
except Exception as e:
    print(e)
    # Worker thread panics; sub-agent exits silently after round 1 of thinking

Observable symptom: The sub-agent starts (logs show 🤔 Thinking... (round 1)) but exits immediately after without calling any tools or returning output. The panic is printed to stderr.


Root Cause

agent.rs:1301 performs a byte-index slice (&s[..180] or similar) on a JSON-serialized string that may contain multi-byte characters. This is safe only for pure ASCII. The fix is to use a char-boundary-safe truncation such as:

// Instead of: &s[..180]
// Use:
let truncated = s.char_indices()
    .take_while(|(i, _)| *i < 180)
    .last()
    .map(|(i, c)| &s[..i + c.len_utf8()])
    .unwrap_or(&s);

Or using the unicode-segmentation crate, or simply s.chars().take(N).collect::<String>().


Impact

  • All sub-agent prompts containing non-ASCII characters (Chinese, Japanese, emoji, etc.) will panic
  • The panic is silent from Python — handle.wait() returns an error but the byte-boundary message only appears on stderr
  • This is a regression in v1.5.6 — the same workflow ran without this panic on v1.5.3/v1.5.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions