Skip to content

fix(schema): remove a map that lives under a nested path - #16461

Merged
vkarpov15 merged 3 commits into
Automattic:masterfrom
luantaraschi:fix/remove-nested-map-path
Aug 21, 2026
Merged

vkarpov15 merged 3 commits into
Automattic:masterfrom
luantaraschi:fix/remove-nested-map-path

Conversation

@luantaraschi

Copy link
Copy Markdown
Contributor

Follow up to #16457, which covered the flat case. The nested branch of Schema#remove() has the same two problems, and one of them throws:

const schema = new Schema({ n: { m: { type: Map, of: Number } } });
schema.remove('n');
// TypeError: Cannot convert undefined or null to object
//     at _deletePath (lib/schema.js:2806:17)

A map registers its values under <path>.$* in paths, so the nested branch walks ['n.m', 'n.m.$*'] and calls _deletePath on each. _deletePath walks schema.tree down the pieces, and by the time it gets to n.m.$* the parent tree.n.m has already been deleted by the previous iteration, so branch is undefined and the delete throws. $* has no branch of its own in the tree in any case.

So _deletePath now stops when a piece along the way is missing. Nothing to delete is not an error there.

With that out of the way the second problem shows: the nested branch never filtered mapPaths, which is what the flat branch does. Measured after schema.remove('n'), before and after:

paths mapPaths pathType('n.m')
before ['_id'] ['n.m.$*'] real
after ['_id'] [] adhocOrUndefined

So the schema kept answering for a path it had just removed, which is the same thing #16457 described, only reached through a nested parent. Both branches now do the same cleanup.

Test in the remove() block. It fails on master on the first assertion, since remove throws before the rest runs.

test/schema.test.js passes 225. Full npm test here matches master, the only failure being an eachAsync timeout that reproduces on a clean checkout on this machine. eslint is clean.

luantaraschi and others added 3 commits August 19, 2026 21:59
Schema#remove() walks the subpaths of a nested branch and calls
_deletePath on each. A map registers its values under `<path>.$*`, which
has no branch of its own in the tree, and by the time that subpath is
reached its parent has already been deleted in the same pass, so the walk
lands on undefined and the delete throws.

_deletePath now stops when a piece along the way is missing, and the
nested branch filters mapPaths the way the flat branch already does, so
the schema stops answering pathType() for a path it removed.

Follow up to Automattic#16457, which covered the flat case.
Removed commented-out code explaining mapPaths behavior.
Removed commented code regarding synthetic subpaths.
@vkarpov15 vkarpov15 added this to the 9.9.4 milestone Aug 20, 2026
vkarpov15 added a commit that referenced this pull request Aug 21, 2026

@vkarpov15 vkarpov15 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks πŸ‘

@vkarpov15
vkarpov15 merged commit b5939fa into Automattic:master Aug 21, 2026
25 of 26 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.

2 participants