Data format interoperability means that independent producers and consumers can exchange data with an agreed interpretation. Sharing a syntax is one part of that agreement; character encoding, supported values and handling of ambiguous inputs also matter. Serialization and deserialization must preserve the distinctions the application needs.[ref]
Consider the original JSON input {"mode":"fast","mode":"safe"}. RFC8259 says object member names should be unique and warns that duplicate-name handling differs. In Python, the default json.loads result is {'mode': 'safe'}. The same decoder with object_pairs_hook=list instead returns [('mode', 'fast'), ('mode', 'safe')], preserving both pairs.[ref][ref]
The text has not changed, yet one consumer retains one value and another retains both occurrences. Re-encoding the default dictionary cannot recover the discarded occurrence. A consumer can instead use a hook that rejects a repeated name, making the ambiguity explicit before the application acts on it.
An exchange contract can therefore require unique names and a shared duplicate-rejection policy, as well as a character encoding such as UTF-8. That is a stronger agreement than merely saying that both programs support JSON. Data validation then checks application-level requirements on the agreed decoded representation.
Data validation 2026-11-05
Data validation checks a value against stated requirements, such as an allowed data type, range or relationship between fields. Parsing establishes how input fits a syntax; an application's validation rules determine whether the resulting value is suitable for its purpose. In Python, json.loads performs JSON deserialization, but it does not know a particular application's requirements.[ref]
For an original example, suppose a program accepts an exact Python integer object from 0 through 10. Its validation predicate is type(x) is int and 0 <= x <= 10. After JSON decoding, inputs 0, 3 and 10 pass; -1, 11, "3", true and 3.0 fail. All are valid JSON texts. The last input becomes a floating-point object, so this particular rule rejects it even though its numerical value is integral. A different application could deliberately accept it.
The rule must therefore be explicit about its intended distinction. Converting every input to an integer before checking would change what is accepted and could lose information. Validating after such conversion answers a different question from checking the original decoded data type.
Finally, conformity to these rules is not evidence that a value is true. An invented count of 3 passes the range/type check, just as an observed count of 3 would. Validation establishes compliance with the specified predicate; establishing the underlying observation requires separate evidence.
Deserialization 2026-11-05
Deserialization reconstructs values from a representation produced according to a format such as JSON. The decoder's mapping determines the resulting runtime data types. In Python, json.loads maps a JSON object to a dictionary, an array to a list, false to False and null to None by default.[ref]
For an original example, json.loads('{"enabled":false,"items":[null,0,"0"]}') produces {'enabled': False, 'items': [None, 0, '0']}. The last two items differ: the integer zero and a string containing a digit are not interchangeable. The decoder reconstructs nested values rather than returning the displayed source text.
Syntax and application meaning require separate checks. The malformed JSON {"items":[1,2,]} raises JSONDecodeError. By contrast, {"items":"many"} parses successfully but fails a program's requirement that items be a list. That second check is data validation, beyond recognizing the format's syntax.[ref]
Nor does successful deserialization guarantee recovery of every original property. A Python tuple encoded as a JSON array normally returns as a list. A round-trip claim must specify whether it preserves values, runtime types or object identity. Character encoding and parsing contribute to the reconstruction, while the selected mapping determines which distinctions survive.
JSON 2026-11-05
JSON, short for JavaScript Object Notation, is a textual data interchange format used for serialization. Its values are objects, arrays, strings, numbers, Boolean values and null. Object member names are strings; array elements are ordered. A complete JSON text may represent a single value, including a number or string.[ref]
The format's syntax and an implementation's numerical precision are separate. For an original example, consider {"n":9007199254740993}. A JavaScript call to JSON.parse produces a Number whose decimal value is 9007199254740992; the requested integer has rounded to in the double-precision floating-point format. The same input decoded by Python's default json.loads retains the integer 9007199254740993 exactly.
Encoding the digits as {"n":"9007199254740993"} preserves them as a string in both examples, but changes the represented type. Any later numerical interpretation needs an agreed rule. RFC8259 identifies the integer interval for exact agreement with commonly used numerical implementations; it does not restrict valid JSON numerals to that interval.[ref]
For exchange between systems outside a closed ecosystem, RFC8259 requires UTF-8.[ref] Defining a textual format therefore addresses portable syntax, while faithful deserialization also requires agreement about the values an application expects.
Serialization 2026-11-05
Serialization maps structured program data into a representation that can be stored or transmitted, often a sequence of bytes. Deserialization reconstructs data according to that format. A useful format must specify which values and distinctions it preserves; writing an object's display text is not automatically a reversible encoding. JSON is one textual interchange format, with ordered arrays and objects whose member names are strings.[ref]
In Python, let value = {"coords": [2, 5], "ready": True}. Calling json.dumps(value, sort_keys=True, separators=(",", ":"), allow_nan=False) produces {"coords":[2,5],"ready":true}. Encoding this string with UTF-8 gives 29 bytes; json.loads reconstructs a value equal to value. Here serialization connects a nested runtime value, text and an explicit character encoding.[ref]
The preservation claim is deliberately specific. If coords originally contains the tuple (2, 5), the default JSON round trip produces a list instead. Equality of the chosen first example therefore proves neither preservation of every runtime type nor preservation of object identity. Format design requires deciding which such distinctions matter.