Skip to content

Fix thread UnraisableException object to be None - #8326

Merged
youknowone merged 1 commit into
RustPython:mainfrom
kyokuping:fix/thread-unraisable
Jul 22, 2026
Merged

youknowone merged 1 commit into
RustPython:mainfrom
kyokuping:fix/thread-unraisable

Conversation

@kyokuping

@kyokuping kyokuping commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • match CPython's unraisable exception reporting for _thread callbacks
  • expose None as the unraisable exception's object
  • consolidate duplicated logic into report_unraisable_thread_exception()

Summary by CodeRabbit

  • Bug Fixes
    • Improved reporting of uncaught exceptions raised in threads, ensuring clearer “exception ignored” messages.
    • Standardized unraisable exception output to include more relevant thread/function context.
    • Corrected stderr formatting when no associated object is available: messages are now shorter and avoid unnecessary prefixes when appropriate.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Thread exception reporting is centralized through a shared helper for plain and joinable threads. VM stderr formatting now handles unraisable reports with no associated object while preserving representation output for object-backed reports.

Changes

Thread exception reporting

Layer / File(s) Summary
Unraisable stderr formatting
crates/vm/src/vm/mod.rs
write_unraisable_to_stderr now writes message-only output when the object is absent and retains object representation output otherwise.
Thread exception reporting integration
crates/vm/src/stdlib/_thread.rs
A shared helper formats unraisable thread exceptions and is used by both plain and joinable thread runners.

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

Sequence Diagram(s)

sequenceDiagram
  participant ThreadRunner
  participant report_unraisable_thread_exception
  participant VirtualMachine
  ThreadRunner->>report_unraisable_thread_exception: uncaught non-SystemExit exception
  report_unraisable_thread_exception->>VirtualMachine: run_unraisable with thread message
  VirtualMachine->>VirtualMachine: write_unraisable_to_stderr
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: thread unraisable exception reporting now uses None as the object.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions

Copy link
Copy Markdown
Contributor

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[x] test: cpython/Lib/test/test_thread.py (TODO: 3)
[x] test: cpython/Lib/test/test_thread_local_bytecode.py
[x] test: cpython/Lib/test/test_threadsignals.py

dependencies:

dependent tests: (14 tests)
- [ ] concurrent.futures: test_asyncio test_compileall test_concurrent_futures test_context test_genericalias test_inspect test_struct test_wmi
- [x] asyncio: test_asyncio test_external_inspection test_logging test_os test_pdb test_unittest

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated

@kyokuping
kyokuping force-pushed the fix/thread-unraisable branch from 67164b6 to dbaa407 Compare July 19, 2026 16:32
@kyokuping
kyokuping marked this pull request as draft July 19, 2026 16:32

@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: 2

🤖 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 `@crates/vm/src/stdlib/_thread.rs`:
- Around line 569-574: Update the message construction in the thread exception
path around func.as_ref().repr(vm) so repr failures produce a fallback context
string rather than None. Preserve the existing formatted representation when
repr succeeds, and always pass a context message to vm.run_unraisable.

In `@crates/vm/src/vm/mod.rs`:
- Around line 1299-1303: Update the None-object branch in the default unraisable
hook to write msg followed only by a newline, removing the trailing colon from
the format passed to write_to_stderr. Preserve the existing conditional behavior
and formatting for cases where an object is present.
🪄 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: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 0819d4a1-51ee-4fa0-9993-90f546cfd998

📥 Commits

Reviewing files that changed from the base of the PR and between 3290f28 and 67164b6.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_thread.py is excluded by !Lib/**
📒 Files selected for processing (2)
  • crates/vm/src/stdlib/_thread.rs
  • crates/vm/src/vm/mod.rs

Comment on lines +569 to +574
let msg = func
.as_ref()
.repr(vm)
.ok()
.map(|repr| format!("Exception ignored in thread started by {}", repr.as_wtf8()));
vm.run_unraisable(exc, msg, vm.ctx.none());

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Handle repr failures gracefully to ensure the context message is printed.

If func.as_ref().repr(vm) fails, ok() maps the result to None, which suppresses the "Exception ignored in thread started by..." context message entirely. CPython prevents this by using a fallback message when the function's representation cannot be retrieved.

🐛 Proposed fix to provide a fallback
-        let msg = func
-            .as_ref()
-            .repr(vm)
-            .ok()
-            .map(|repr| format!("Exception ignored in thread started by {}", repr.as_wtf8()));
-        vm.run_unraisable(exc, msg, vm.ctx.none());
+        let msg = match func.as_ref().repr(vm) {
+            Ok(repr) => format!("Exception ignored in thread started by {}", repr.as_wtf8()),
+            Err(_) => "Exception ignored in thread started by <function repr() failed>".to_owned(),
+        };
+        vm.run_unraisable(exc, Some(msg), vm.ctx.none());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let msg = func
.as_ref()
.repr(vm)
.ok()
.map(|repr| format!("Exception ignored in thread started by {}", repr.as_wtf8()));
vm.run_unraisable(exc, msg, vm.ctx.none());
let msg = match func.as_ref().repr(vm) {
Ok(repr) => format!("Exception ignored in thread started by {}", repr.as_wtf8()),
Err(_) => "Exception ignored in thread started by <function repr() failed>".to_owned(),
};
vm.run_unraisable(exc, Some(msg), vm.ctx.none());
🤖 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 `@crates/vm/src/stdlib/_thread.rs` around lines 569 - 574, Update the message
construction in the thread exception path around func.as_ref().repr(vm) so repr
failures produce a fallback context string rather than None. Preserve the
existing formatted representation when repr succeeds, and always pass a context
message to vm.run_unraisable.

Comment thread crates/vm/src/vm/mod.rs
Comment on lines +1299 to 1303
if self.is_none(object) {
if let Some(msg) = msg {
write_to_stderr(&format!("{msg}:\n"), &stderr, self);
}
} else {

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the trailing colon when formatting msg without an object.

When object is None, the default unraisable hook should write the message followed by a newline, without a trailing colon. Currently, a thread exception will be incorrectly logged as Exception ignored in thread started by <function>: instead of matching CPython's format.

🐛 Proposed fix
         if self.is_none(object) {
             if let Some(msg) = msg {
-                write_to_stderr(&format!("{msg}:\n"), &stderr, self);
+                write_to_stderr(&format!("{msg}\n"), &stderr, self);
             }
         } else {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if self.is_none(object) {
if let Some(msg) = msg {
write_to_stderr(&format!("{msg}:\n"), &stderr, self);
}
} else {
if self.is_none(object) {
if let Some(msg) = msg {
write_to_stderr(&format!("{msg}\n"), &stderr, self);
}
} else {
🤖 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 `@crates/vm/src/vm/mod.rs` around lines 1299 - 1303, Update the None-object
branch in the default unraisable hook to write msg followed only by a newline,
removing the trailing colon from the format passed to write_to_stderr. Preserve
the existing conditional behavior and formatting for cases where an object is
present.

@kyokuping
kyokuping marked this pull request as ready for review July 19, 2026 16:41
@kyokuping
kyokuping marked this pull request as draft July 19, 2026 18:12
@youknowone youknowone added the z-ca-2026 Tag to track Contribution Academy 2026 label Jul 20, 2026
@kyokuping
kyokuping marked this pull request as ready for review July 20, 2026 13:02

@youknowone youknowone left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

huh, didn't know about this. Thank you!

@youknowone
youknowone merged commit dd9bce5 into RustPython:main Jul 22, 2026
50 of 51 checks passed
@kyokuping
kyokuping deleted the fix/thread-unraisable branch August 8, 2026 05:58
youknowone pushed a commit that referenced this pull request Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

z-ca-2026 Tag to track Contribution Academy 2026

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants