Skip to content

1.3.33: instancePath and schemaPath do not escape / and ~ in property names #1694

Description

@vimhead

Summary

In typebox@1.3.33, error paths concatenate property names without JSON Pointer escaping. A literal key "a/b" and a nested a.b both produce instancePath: "/a/b". A literal "a~1b" key produces /a~1b, which decodes to the different key "a/b".

Validation correctly rejects the values. The problem is the location reported by the diagnostics: even TypeBox's own Value.Pointer.Get(value, error.instancePath) retrieves the wrong value. schemaPath has the same escaping problem.

Self-contained reproduction

Tested with Node.js 24.21.0 on macOS arm64, using a fresh installation of typebox@1.3.33 (the typebox package, not @sinclair/typebox). No settings or schema transforms are involved.

mkdir typebox-pointer-repro
cd typebox-pointer-repro
npm init -y
npm install --save-exact typebox@1.3.33

Save this as repro.mjs, then run node repro.mjs:

import assert from 'node:assert/strict'
import Type from 'typebox'
import Value from 'typebox/value'

const schema = Type.Object({
  'a/b': Type.Number(),
  a: Type.Object({ b: Type.Number() }),
  'a~1b': Type.Number()
})
const value = { 'a/b': 'literal slash', a: { b: 'nested' }, 'a~1b': 'literal tilde' }
const errors = Value.Errors(schema, value)

console.log(JSON.stringify(errors.map(error => ({
  instancePath: error.instancePath,
  schemaPath: error.schemaPath,
  resolvedValue: Value.Pointer.Get(value, error.instancePath)
})), null, 2))

assert.deepEqual(errors.map(error => error.instancePath), ['/a~1b', '/a/b', '/a~01b'])

Actual output

[
  {
    "instancePath": "/a/b",
    "schemaPath": "#/properties/a/b",
    "resolvedValue": "nested"
  },
  {
    "instancePath": "/a/b",
    "schemaPath": "#/properties/a/properties/b",
    "resolvedValue": "nested"
  },
  {
    "instancePath": "/a~1b",
    "schemaPath": "#/properties/a~1b",
    "resolvedValue": "literal slash"
  }
]

The assertion fails with actual paths ['/a/b', '/a/b', '/a~1b'].

Expected output

[
  {
    "instancePath": "/a~1b",
    "schemaPath": "#/properties/a~1b",
    "resolvedValue": "literal slash"
  },
  {
    "instancePath": "/a/b",
    "schemaPath": "#/properties/a/properties/b",
    "resolvedValue": "nested"
  },
  {
    "instancePath": "/a~01b",
    "schemaPath": "#/properties/a~01b",
    "resolvedValue": "literal tilde"
  }
]

Per RFC 6901 §3, property-name tokens must encode ~ as ~0 and / as ~1, while preserving the separators between tokens. This is important for assigning errors to fields and resolving their values or schemas.

Source verification

Also reproduced directly from a fresh clone at 055e51c with Deno 2.7.14. Focused tests cover instancePath, schemaPath, and pointer round-tripping in both Value.Errors(schema, value) and Compile(schema).Errors(value); all six diagnostic assertions fail, while valid/invalid boolean validation checks pass. The existing three Value.Errors tests also pass.

The relevant construction is in ErrorProperties, which inserts the raw key into both paths.

Related history: #643 reported the equivalent ambiguity in the older API and was reported fixed in 0.31.19. This report concerns the current 1.3.33 package and its instancePath / schemaPath diagnostics.

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