Detect broken XML paths and offer to fix on form load#1220
Detect broken XML paths and offer to fix on form load#1220jingcheng16 wants to merge 3 commits intomasterfrom
Conversation
946c73e to
a0ccc94
Compare
a0ccc94 to
b359ba4
Compare
When a form has hand-edited XML with wrong control element paths, detect the broken paths during parsing by matching leaf names against existing data nodes. After loading, show a modal listing the broken paths and their corrections with a "Fix and Reload" button that corrects the XML and reloads the form. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Neither button should be pre-focused so the user makes a deliberate choice between "Fix and Reload" and "Ignore". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b359ba4 to
b9ac428
Compare
Apply the same leaf-name matching to bind elements. When a bind references a path like /data/total_score but the data node exists at /data/sec_scoring/total_score, include it in the path corrections shown in the modal instead of silently discarding the bind. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
millerdev
left a comment
There was a problem hiding this comment.
I don't think we should attempt to fix manual XML editing mistakes. All kinds of errors could be made, and there is no way we can possibly handle all of them. We may end up breaking the form even more with automated fixups. At best we would be guessing, which violates the Zen "In the face of ambiguity, refuse the temptation to guess."
| * @param path - the broken path (e.g., "/data/members_repeat") | ||
| * @returns - the matching DataBindOnly mug, or null | ||
| */ | ||
| function findDataNodeByLeafName(form, path) { |
There was a problem hiding this comment.
What if multiple data nodes are matched? It doesn't know which is the correct one. As implemented, it chooses the last match.
Imagine a scenario where two different mugs are missing data nodes, and both have the same node leaf name. I think both would be assigned the same data node, which would be incorrect.
@millerdev It's true. 😞 Then in this case, what can we do to help user except for ask them to delete the repeat group and rebuild it? I built this mainly because I think all warning message is misleading, and user is not able to fix it in the UI. |
That is one option. If they have edited XML by hand, they may know enough to fix the error by editing XML, so maybe that could be suggested first? If they do not know how to fix it then the fall-back option of deleting the group and rebuilding is probably the best path forward. It's true, the error message you referenced is pretty technical. I think it is a reasonable and correct error message if they have made a mistake while hand-editing XML. At the point of seeing it they should know that they have made a mistake while editing XML, and should probably attempt to fix it there rather than in the UI. |

Product Description
When a form has hand-edited XML with wrong paths (e.g., a repeat group referencing
/data/members_repeatinstead of/data/sec_members/members_repeat), the form silently breaks — Question ID becomes blank and uneditable, and saving the form causes data loss. User is confused and don't know how to fix it, fill in a Question ID won't work.After this change, a modal appears on form load showing the broken paths and their corrections (e.g.,
/data/members_repeat→/data/sec_members/members_repeat), with a "Fix and Reload" button that corrects the XML automatically.I then realized I can apply same logic to broken path in bind node.


Thus the modal will become the following:
Technical Summary
Ticket: https://dimagi.atlassian.net/browse/SAAS-19569
Why Question ID breaks
When a control element's path doesn't resolve via
getMugByPath, the parser creates an orphaned "control-only" mug with no data node. This causes a chain of failures:isControlOnly = true→absolutePathreturns null (code)absolutePathnull →hashtagPathnullnodeIDsetter callsmoveMug("rename", value)which skips the entire rename block for control-only mugsHow this PR fixes it
During parsing, when
getMugByPathfails,findDataNodeByLeafNamesearches for an unclaimed DataBindOnly mug with the same node name (e.g., findsmembers_repeatat/data/sec_members/members_repeat). If found, the correction is stored onform.pathCorrections. After parsing,showPathCorrectionModaldisplays the corrections. "Fix and Reload" does a find-and-replace on the raw XML and reloads the form, which resolves the control to the correct data node and restores Question ID.Feature Flag
N/A
Safety Assurance
Safety story
This only activates when
getMugByPathreturns null for a control element's path — a case that previously resulted in silent data loss. Normal forms with valid paths are unaffected. The fix is opt-in via the modal (user can click "Ignore" to skip).Automated test coverage
No existing tests cover malformed XML path handling. Manual testing with broken XML files confirms the modal appears and fix works correctly.
QA Plan
/data/members_repeat→/data/sec_members/members_repeatRollback instructions
Labels & Review
🤖 Generated with Claude Code