Repository navigation
fix: handle None return from error handler in no-output background callbacks - #4012
dajiaohuang wants to merge 10 commits into
Conversation
…llbacks When a background callback with no outputs raises an exception, the error handler is called. If the error handler returns None, the code was incorrectly setting output_value = NoUpdate(), which then triggered an InvalidCallbackReturnValue exception at the output validation step. This change adds the same output_spec check that exists in the non-background callback path (line 866) to the background callback path (line 635), ensuring that NoUpdate() is only set when there are actual outputs to update. Fixes plotly#3628
|
Thanks for the PR! Could you please look into the test failures and see what's going on? |
T4rk1n
left a comment
There was a problem hiding this comment.
Works good, and the lcbc019 test covers it. One gap: the job-cancel branch a few lines above has the same NoUpdate() for no-output callbacks, so cancelling a no-output background callback still raises InvalidCallbackReturnValue. Can you fix that here too, since it's the same bug? Please also add a CHANGELOG entry under Fixed for #3628.
|
感谢你的反馈!你说得对,测试确实过度使用了 mock,我会简化测试方法。 |
- The cancelled-job branch in _handle_rest_background_callback now sets NoUpdate() only when output_spec is truthy (callbacks with outputs), matching the error-handler guard added earlier. Without outputs, output_value stays None so _prepare_response does not raise InvalidCallbackReturnValue. - Replace the heavily-mocked test_mcpbg012 with two integration-style tests that register a real no-output background callback via @app.callback and exercise both the completed and cancelled paths through the actual MCP tasks/result endpoint. - Add CHANGELOG entry for plotly#3628 / plotly#4012.
|
Addressed the review feedback:
|
…llback-error-handler # Conflicts: # CHANGELOG.md
|
Fixed the current-head MCP unit failures in f5cde05. No-output callback IDs are hashes, not component.property IDs, so tasks/result must not split them. It also now formats the framework's normal PreventUpdate result instead of returning an MCP internal error. The existing cancel output_spec guard remains intact. Validation: reproduced both failures from run 38700521782, then passed all 198 MCP unit tests and a retained headless browser/HTTP cancellation regression. Used the generated components and renderer from that run's official dash-packages artifact; no generated files were edited. Local environment: Windows/Python 3.13, unrelated pytest plugin autoload disabled. A browser completion variant timed out waiting for its Windows background process, so completion is covered locally by the real-dispatch unit test, not claimed as browser-validated. The benchmark process exited successfully in run 38700521890; that job failed when its comment POST received HTTP 403 (Resource not accessible by integration). No benchmark thresholds or workflow permissions changed. |
|



Summary
When a background callback with no outputs raises an exception, the error handler is called. If the error handler returns
None, the code was incorrectly settingoutput_value = NoUpdate(), which then triggered anInvalidCallbackReturnValueexception at the output validation step.Fix
This change adds the same
output_speccheck that exists in the non-background callback path to the background callback path at_callback.py:635, ensuring thatNoUpdate()is only set when there are actual outputs to update.Testing
The issue includes a minimal reproducible example that can be used to verify the fix.
Related Issue
Fixes #3628