Skip to content

add/move/copy at the whole-document pointer crash when the root is an array #190

Description

@feiiiiii5

add with a whole-document pointer ("path": "") works when the document root is an object but crashes when it is an array.

>>> import jsonpatch
>>> jsonpatch.apply_patch(['foo', 'bar'], [{'op': 'add', 'path': '', 'value': {'replaced': True}}])
TypeError: '>' not supported between instances of 'NoneType' and 'int'

move and copy to the root fail the same way on an array root, because both delegate to AddOperation:

>>> jsonpatch.apply_patch(['foo', 'bar'], [{'op': 'move', 'from': '/0', 'path': ''}])
TypeError: '>' not supported between instances of 'NoneType' and 'int'
>>> jsonpatch.apply_patch(['foo', 'bar'], [{'op': 'copy', 'from': '/1', 'path': ''}])
TypeError: '>' not supported between instances of 'NoneType' and 'int'

Why it is a defect rather than an unsupported case

  • replace at the root already works on an array root — it returns the new document.
  • add at the root already works on an object root.
  • A bare TypeError is not part of the documented exception hierarchy, so a caller writing except jsonpatch.JsonPatchException: cannot catch it.

RFC 6902 has exactly one root location, so all four combinations should agree.

Root cause

AddOperation.apply obtains subobj, part = self.pointer.to_last(obj), and a whole-document pointer yields part is None. The MutableMapping branch handles that (obj = value # we're replacing the root); the MutableSequence branch went straight to elif part > len(subobj), comparing None against an int. ReplaceOperation.apply checks if part is None: return value before branching, so it never hit this.

PR #15 ("Fixed replacing whole document", merged 2013) added exactly this handling to the code that existed then; the class-based refactor in b8083d70 (2020) kept it in the mapping branch and the sequence branch never received it.

Suggested fix

Give the MutableSequence branch the same part is None arm as the mapping branch, returning value. No test covers the array root.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions