Why does RFC 7951 encode a YANG uint64 counter as a JSON string, and an empty-type leaf as [null], in RESTCONF bodies?
answer
- what a double can hold exactly
- two to the fifty-third
- null often reads as absent
- presence is the whole value
basics
~20 sMany JSON parsers store numbers as IEEE 754 doubles, exact only up to 2^53, so int64, uint64 and decimal64 travel as strings; and many treat a null member as missing, so an empty leaf is the one-element array [null].
solid answer
~40 sRFC 7951 Section 6.1 sends `int8` through `uint32` as JSON numbers but `int64`, `uint64` and `decimal64` as JSON strings holding the YANG lexical form, following the I-JSON advice for values beyond double precision. RFC 8259 notes that parsers agree exactly on integers within `±(2^53 - 1)`, while a `yang:counter64` such as an interface octet counter runs to `2^64 - 1`; a parser that rounds it loses the low digits silently. A YANG `empty` leaf carries meaning by presence alone, so Section 6.9 encodes it as `[null]`: the RFC rejects bare `null` because many languages treat a null member as absent. The same type-driven logic makes `bits` a space-separated string and lets a `union` use the JSON type to pick its member.
go deeper
Recall which YANG numeric types are strings in RESTCONF JSON (int64, uint64, decimal64) and that an empty leaf is written [null].
Explain the double-precision limit behind the string rule and why bare null was rejected for empty, and give the bits and union encodings.
Show the production consequence: a 64-bit counter parsed as a double silently loses precision within days on a fast link, so parse those strings into exact types.
Discuss where schema-aware parsing belongs in an automation stack so that type-driven encodings are handled once, not rediscovered by every consumer.
## JSON values carry types; YANG types are richer A JSON value is a string, a number, `true`/`false`, `null`, an array or an object. A **YANG** leaf has a precise type: `uint8`, `int64`, `decimal64`, `boolean`, `empty`, `bits`, `enumeration` and more. **RFC 7951** (Section 6) fixes one JSON representation per YANG type so that, as Section 3 puts it, the partial type information JSON carries "is never in conflict with the data type" of the leaf. Two of its choices look strange until you see what they protect against. ## Why 64-bit numbers are strings | YANG type | JSON value | Example | |---|---|---| | `int8`, `int16`, `int32`, `uint8`, `uint16`, `uint32` | number | `"mtu": 1500` | | `int64`, `uint64`, `decimal64` | **string** with the YANG lexical form | `"in-octets": "123"` | JSON's grammar puts no limit on a number, but **parsers** do. RFC 8259 Section 6 observes that IEEE 754 binary64 (double precision) is what most software uses, and that integers in the range `[-(2^53)+1, (2^53)-1]` are interoperable in the sense that implementations agree exactly on their values. RFC 7951 follows the I-JSON recommendation (RFC 7493) to carry numbers beyond that range as strings, and applies it to the whole 64-bit family rather than to individual large values, so a value's encoding never depends on its size. A worked example shows the risk is not theoretical: 1. An interface's `in-octets` leaf in `ietf-interfaces` (RFC 8343) is a `yang:counter64`, a `uint64` (defined in `ietf-yang-types`, RFC 9911, which obsoletes RFC 6991). Its maximum is `2^64 - 1 = 18,446,744,073,709,551,615`. 2. `2^53 = 9,007,199,254,740,992`. 3. A 100 Gb/s link at line rate moves `100e9 / 8 = 12.5e9` bytes per second. 4. `9,007,199,254,740,992 / 12,500,000,000 ≈ 720,576` seconds, about **8.3 days**. Starting from zero, after roughly eight days of full load that counter exceeds what a double holds exactly, and a client that parsed it as a JSON number starts computing rates from rounded values with no error raised. Encoding it as `"in-octets": "9007199254740993"` lets the client choose an exact integer type. `decimal64` is a string for the same reason: with up to 18 fraction digits it is a fixed-point value that a binary double cannot represent exactly, and its lexical form (RFC 7950 §9.3.1, an optional sign, digits, optionally a period and more digits) survives intact inside a string. The integer lexical form is plain decimal digits; YANG's hexadecimal and octal notations exist only for default values written in a module. ## Why empty is [null] A YANG leaf of type **`empty`** has no value: it "conveys information by its presence or absence" (RFC 7950 §9.11). In XML that is simply `<shutdown/>`. JSON needs something on the right-hand side of the colon. RFC 7951 Section 6.9 chose `[null]`, an array whose only element is `null`, and explains why bare `null` was rejected: in common programming languages a member whose value is `null` is treated as if the member were not there, which would turn "present" into "absent" in transit. `[null]` is treated as an atomic scalar value, and inside `anydata` content RFC 7951 allows `null` only in that single-element array. RESTCONF users meet it sooner than they expect: the YANG Patch status reply of RFC 8072 reports success with an `ok` leaf of type `empty`, so a successful patch comes back as `"ok": [null]`. ## The rest of the type table - **`boolean`**: the literals `true` and `false`, never strings. - **`enumeration`**: a string with the enum's name. - **`bits`**: a single string, the space-separated names of the bits that are set; a zero-length string means none are set. - **`binary`**: a base64 string, the one place RFC 7951 deviates from I-JSON, which prefers base64url. - **`union`**: the JSON type helps choose the member type. For a union of `uint16` and `string`, `"bar": 13.5` is an error (a number, but not a valid `uint16`), while `"bar": "1"` is the string member; XML has no such signal. ## What a client should take from this - Build bodies from the schema: a leaf's YANG type, not the look of its value, decides whether it is a number or a string. - Parse 64-bit values from their strings into exact integer or decimal types; never let a generic JSON number parser touch them. - To set an empty leaf send `[null]`; to clear it remove the leaf, because there is no `false` for `empty`. - Expect a server that validates RFC 7951 strictly to reject a `uint64` leaf sent as `123` or an `empty` leaf sent as `true`, even though both are valid JSON.
- How does RFC 7951 resolve a YANG union of uint16 and string when the JSON value is 13.5 or "1"?Section 6.10 says the JSON type must be taken into account. `13.5` is a JSON number but not a valid `uint16`, so it is an error; it cannot fall through to the string member. `"1"` is a JSON string, so it is the string member, not the number 1. In XML, `<bar>13.5</bar>` would be accepted as the string member because XML carries no type signal.
- How do you turn off a YANG empty leaf over RESTCONF if there is no false value?You remove the leaf. An `empty` leaf means something only by being present, so `[null]` sets it and absence clears it: delete that leaf's resource, or replace its parent with a body that omits it. Sending `false`, `null` or `[]` is not a valid RFC 7951 value for an `empty` leaf.
saying these in an interview costs you the question
- A uint64 can go as a bare JSON number because JSON numbers are unbounded
- Only values above 2^53 need quoting; small int64 values stay numbers
- An empty-type leaf is encoded as true or as null
- Every YANG integer, including uint32, travels as a JSON string
- A YANG bits value is a JSON array of bit names