Conversation
Mukller
left a comment
There was a problem hiding this comment.
Self-Review
Root Cause
escapes dots in component IDs with so they don't collide
with the separator between component-id and property in the callback ID string.
This is correct for string IDs (the JS side un-escapes when splitting).
For dict IDs, returns valid JSON (e.g.
). After , the dot inside
the JSON string value becomes — an invalid JSON escape sequence — and
throws .
Why is the right fix
is a standard JSON Unicode escape (U+002E FULL STOP). It is
valid inside JSON strings and decodes it back to automatically.
The frontend receives the original dict value unchanged. No JS changes are needed.
Correctness matrix
| ID type | Value | Callback ID (before) | Callback ID (after) |
|---|---|---|---|
| string | unchanged | ||
| dict | — BROKEN | ✓ | |
| dict multi-dot | — BROKEN | ✓ | |
| dict, no dot | unchanged | unchanged |
What does NOT change
- — unchanged; still used for runtime input matching
- Pattern-matching wildcards (//) — no dots → unaffected
- Multi-output format () — structural separators unaffected
- — still ; callers that parse the JSON portion
use which correctly decodes → - No JavaScript changes required — handles natively
|
Thanks for the PR! Our team will review and follow up. |
T4rk1n
left a comment
There was a problem hiding this comment.
Can you add a test for this?
|
Added tests in tests/unit/test_callback_unit.py:
Also pushed a branch update to pick up latest main. |
T4rk1n
left a comment
There was a problem hiding this comment.
Fix is right. Escaping has to stay (the ... multi-output separator in split_callback_id would otherwise trip on dots inside a dict value), and \u002e keeps the escape while staying valid JSON — parsePMCId keys off the last } and rsplit(".", 1) on the backend both round-trip cleanly. create_callback_id is the only place that does this escaping, so the fix is complete.
Can you add a CHANGELOG.md entry under Fixed, linking back to #3480? One inline note below.
| """Test that callback is properly exported from dash module.""" | ||
| assert hasattr(dash, "callback") | ||
| assert dash.callback is callback | ||
| """Unit tests for callback decorator behavior - no browser required.""" |
There was a problem hiding this comment.
This file got converted to CRLF, which is why it shows as a full rewrite (132 deletions) instead of just the three added tests. Can you convert it back to LF so the diff is only the new tests?
The file was committed with CRLF line endings, which made the diff against dev show a full-file rewrite (132 deletions) instead of just the three added tests. Normalized to LF so the diff contains only the new tests.
|
|
Fixed in cd6bf96 — The file had been committed with CRLF endings, so the diff against
The cause was Tests: One thing worth flagging for the project rather than for this PR: with no |



Problem
Fixes #3480.
When a dict component ID contains a dot in one of its string values (e.g.
id={"component": "button.dot"}), opening the app results in a blank page and
SyntaxError: Bad escaped character in JSON in the browser console.
Root cause
In _utils.py, create_callback_id calls x.component_id_str().replace(".", ".")
on every component ID. For string IDs this is fine, but dict IDs are serialized
as JSON. After the replacement, a value like "button.dot" becomes "button.dot"
inside the JSON fragment. The frontend then calls JSON.parse on this fragment
(in parsePMCId and callbacks.ts) and encounters . which is NOT a valid JSON
escape sequence -> SyntaxError.
Fix
For dict IDs, replace . with . (the standard JSON Unicode escape for
U+002E FULL STOP) instead of .:
the original dict value unchanged.
Before / After
component_id = {"component": "button.dot"}, property = "children"
Before (broken): {"component":"button.dot"}.children
-> JSON.parse throws SyntaxError
After (fixed): {"component":"button.dot"}.children
-> JSON.parse returns {"component": "button.dot"} correctly
Closes #3480.