Skip to content

Fix/issue 1330 taskid null render crash #1330 - #1331

Merged
claude-code-best merged 2 commits into
mainfrom
fix/issue-1330-taskid-null-render-crash
Aug 3, 2026
Merged

Fix/issue 1330 taskid null render crash #1330#1331
claude-code-best merged 2 commits into
mainfrom
fix/issue-1330-taskid-null-render-crash

Conversation

@claude-code-best

@claude-code-best claude-code-best commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of tool progress messages with missing data, preventing message processing errors.
    • Isolated tool-result rendering failures so they no longer disrupt the surrounding message display.
  • Tests

    • Added regression coverage for tool progress messages with null or undefined data.

claude-code-best and others added 2 commits August 2, 2026 23:02
filterToolProgressMessages 放行 data:null 的 progress 消息(结构漏洞),
UserToolSuccessMessage 的工具结果渲染不在嵌套边界内(任何字段访问崩溃
都会撕裂整个 MessagesBoundary)。补齐两层防线:
- Tool.ts: data != null 过滤 + UserToolSuccessMessage 结果槽位加
  SentryErrorBoundary(name=ToolResultMessage)
- BashTool/PowerShellTool/MonitorTool/AttachmentMessage/
  UserTeammateMessage/TaskAssignmentMessage 的 taskId 读取改可选链
- 新增 filterToolProgressMessages data:null 回归测试

Co-Authored-By: deepseek-v4-flash <deepseek-ai@claude-code-best.win>
review 后移除 8 处纯防御性可选链改动(原有守卫已完整),仅保留:
- filterToolProgressMessages 拒绝 data 为 null 的 progress 消息
- ToolResultMessage 边界包裹,隔离工具结果 UI 渲染崩溃
- AssistantToolUseMessage / messages.ts 同源 data 空值守卫

Co-Authored-By: deepseek-v4-flash <deepseek-ai@claude-code-best.win>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds null checks for tool-progress message data and wraps tool-result rendering in a named SentryErrorBoundary. Tests cover filtering of messages with nullish data.

Changes

Tool message safety

Layer / File(s) Summary
Null-safe progress processing
src/Tool.ts, src/components/messages/AssistantToolUseMessage.tsx, src/utils/messages.ts, src/__tests__/Tool.test.ts
Progress filters and message lookups check for non-null data before reading type. Tests cover null, undefined, and valid tool-progress data.
Tool-result rendering boundary
src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx
Tool-result content is wrapped in a named SentryErrorBoundary with the name ToolResultMessage.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the null-related render crash that the pull request fixes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-1330-taskid-null-render-crash

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/utils/messages.ts (1)

1279-1283: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a type guard instead of asserting the nullable shape.

The assertion does not validate the runtime object or hookEvent. If a malformed hook_progress payload lacks a valid hookEvent, the code inserts an invalid key into inProgressHookCounts. Reuse a guard that validates both type and hookEvent before updating the map.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/messages.ts` around lines 1279 - 1283, Replace the nullable type
assertion in the progress-data handling with the existing type guard that
validates both the payload type and hookEvent before entering the hook_progress
branch. Update the condition around inProgressHookCounts so malformed payloads
are ignored and only validated HookEvent values become map keys.

Source: Coding guidelines

src/__tests__/Tool.test.ts (1)

207-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the lookup-builder path.

This test covers filterToolProgressMessages only. Add or confirm tests for buildMessageLookups with data: null and data: undefined, so the changed progressData.type path also remains protected from regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/Tool.test.ts` around lines 207 - 221, Add tests for
buildMessageLookups covering messages whose data is null and undefined,
verifying they are safely ignored without accessing progressData.type or
throwing. Keep the existing filterToolProgressMessages regression test unchanged
and assert the lookup-builder output remains valid for the remaining data.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx`:
- Around line 112-121: Move the synchronous tool renderer call into a dedicated
child component, then render that child inside the named SentryErrorBoundary in
UserToolSuccessMessage so renderer exceptions are caught. Add a regression test
covering a synchronous throw from renderToolResultMessage and verify the
boundary fallback replaces only the tool-result row.

---

Nitpick comments:
In `@src/__tests__/Tool.test.ts`:
- Around line 207-221: Add tests for buildMessageLookups covering messages whose
data is null and undefined, verifying they are safely ignored without accessing
progressData.type or throwing. Keep the existing filterToolProgressMessages
regression test unchanged and assert the lookup-builder output remains valid for
the remaining data.

In `@src/utils/messages.ts`:
- Around line 1279-1283: Replace the nullable type assertion in the
progress-data handling with the existing type guard that validates both the
payload type and hookEvent before entering the hook_progress branch. Update the
condition around inProgressHookCounts so malformed payloads are ignored and only
validated HookEvent values become map keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4e8bbf9d-590f-49f0-a059-31bf3e63df48

📥 Commits

Reviewing files that changed from the base of the PR and between 4e988ad and 5aa20af.

📒 Files selected for processing (5)
  • src/Tool.ts
  • src/__tests__/Tool.test.ts
  • src/components/messages/AssistantToolUseMessage.tsx
  • src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx
  • src/utils/messages.ts

Comment on lines +112 to +121
{/*
Tool-provided result UIs are rendered from runtime data
(message.toolUseResult). Resumed transcripts deserialize it via raw
JSON.parse (parseJSONL), so a partial/corrupt/old-format result can
crash renderToolResultMessage on first field access
(anthropics/claude-code#39817, claude-code-best/claude-code#1330).
Keep the result slot behind its own boundary so a bad result only
degrades that row instead of tearing down the whole Messages tree.
*/}
<SentryErrorBoundary name="ToolResultMessage">{wrappedMessage}</SentryErrorBoundary>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
fd -a 'UserToolSuccessMessage\.tsx$' . || true

echo "== file outline =="
ast-grep outline src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx --view expanded || true

echo "== relevant lines =="
sed -n '1,180p' src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx

echo "== search renderToolResultMessage definitions/usages =="
rg -n "renderToolResultMessage|function renderToolResultMessage|const renderToolResultMessage|export .*renderToolResultMessage" src || true

echo "== search SentryErrorBoundary =="
rg -n "SentryErrorBoundary|class SentryErrorBoundary|function SentryErrorBoundary" src || true

Repository: claude-code-best/claude-code

Length of output: 11212


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== SentryErrorBoundary implementation =="
sed -n '1,90p' src/components/SentryErrorBoundary.tsx

echo "== Tool renderToolResultMessage signature and comments =="
sed -n '550,610p' src/Tool.ts

echo "== test files mentioning UserToolSuccessMessage or ToolResultMessage =="
rg -n "UserToolSuccessMessage|ToolResultMessage|SentryErrorBoundary.*ToolResult|toolUseResult" src/utils src/components/messages/src src --glob '*test*' --glob '*Test*' || true

Repository: claude-code-best/claude-code

Length of output: 5381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import ast
from pathlib import Path
import re

path = Path("src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx")
src = path.read_text()

# Deterministic check based on source order and lexical assignment to JSX children.
try:
    tree = ast.parse(src)
except Exception as e:
    print(f"parse_error: {type(e).__name__}: {e}")
    raise

assignments = {}
calls = []
boundary = None
func = None
for node in tree.body:
    if isinstance(node, ast.FunctionDef) and node.name == "UserToolSuccessMessage":
        func = node
        for child in ast.walk(node):
            if isinstance(child, ast.Return) and child.value is not None and isinstance(child.value, ast.Subscript):
                # JSX subscripts: expressions in the JSX tree appear as Subscript nodes in this TypeScript-like AST if imported/typed.
                # Use text pattern for this simple check rather than parsing JSX into AST.
                pass
        calls = []
        boundary = None
        for child in ast.walk(node):
            if isinstance(child, ast.Call):
                calls.append(ast.get_source_segment(src, child))
            if isinstance(child, ast.Assign) and len(child.targets) == 1 and isinstance(child.targets[0], ast.Name) and child.targets[0].id == "wrappedMessage":
                assignments[child.targets[0].id] = ast.get_source_segment(src, child.value)

        # Find boundary text and its child expression.
        text = src[node.lineno-1:tree.body.index(func)+1]
        for m in re.finditer(r"<SentryErrorBoundary[^>]*>(.*?)</SentryErrorBoundary>", text, flags=re.S):
            boundary = ast.get_source_segment(src, node).find(m.group(0))
            print("boundary_text", m.group(0))
        render_call = next((x for x in calls if "renderToolResultMessage" in str(x)), None)
        wrapped_text = assignments.get("wrappedMessage")
        print("render_call_present", render_call is not None)
        print("wrapped_message", wrapped_text)
        print("boundary_text_contains_render_call", boundary is not None and render_call in boundary if render_call else False)
        print("boundary_text_contains_wrappedMessage", boundary is not None and wrapped_text is not None and "wrappedMessage" in m.group(0) if render_call else False)
        break
PY

Repository: claude-code-best/claude-code

Length of output: 517


Move the synchronous tool renderer under SentryErrorBoundary.

tool.renderToolResultMessage runs before React creates SentryErrorBoundary, so a synchronous exception still leaves UserToolSuccessMessage. Move the renderer call into a child component and render that child inside the named boundary. Add a regression test where renderToolResultMessage throws synchronously.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx`
around lines 112 - 121, Move the synchronous tool renderer call into a dedicated
child component, then render that child inside the named SentryErrorBoundary in
UserToolSuccessMessage so renderer exceptions are caught. Add a regression test
covering a synchronous throw from renderToolResultMessage and verify the
boundary fallback replaces only the tool-result row.

@claude-code-best
claude-code-best merged commit 6ac790e into main Aug 3, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant