Make the contract choice explicit

A JSON object associates string member names with values. For a payload that needs application-defined member names, choose among three distinct contracts: an unrestricted bag, a map whose dynamic values must be null, or a fixed object that forbids unlisted members.

A null-marker map is the middle option. It leaves room for dynamic names but constrains each unmatched member to the null type. This article treats the meaning of that marker, its naming rules, ownership, migration path, and invalid-input response as application decisions—not as meanings supplied by JSON Schema.

Read the two supplied references as shared official JSON Schema guidance, not as independent confirmation. The discussion is bounded to their object and null material and does not make validator- or draft-specific promises.

Four-case decision table

Illustrative contract comparison for a fixed-name area plus possible dynamic members
CaseInstance shapeEffect of propertiesEffect of permissive additional propertiesEffect of closing additional propertiesEffect of applying a null schema to additional propertiesInference to rejectContract ownerBounded application-owned action
Declared properties onlyOnly names already listed by the contract appear.The schemas attached to listed names govern those members.No unmatched member is present, so this setting adds nothing for this case.No unmatched member is present, so closure adds nothing for this case.No unmatched member is present, so the dynamic-value rule has nothing to check.A listed name must be present merely because it appears in properties.Schema maintainerList fixed fields in properties; add required only where the application needs presence.
Undeclared property whose value is nullA dynamic name appears with a null value.That unmatched name is outside the named-property schemas.The member is allowed without a value constraint.The member is rejected because its name is not listed.The member is allowed because null satisfies the dynamic-member schema.Null represents a missing member.Schema maintainer and application contract ownerDocument a present null member as the sole marker value if that is the chosen local convention.
Undeclared property whose value is falseA dynamic name appears with the Boolean value false.That unmatched name is outside the named-property schemas.The member is allowed without a value constraint.The member is rejected because its name is not listed.The member is rejected because false does not satisfy a null-only schema.Key presence alone proves the intended marker state.Schema maintainer and application contract ownerReject or migrate this legacy representation according to a documented local compatibility rule.
Undeclared property whose value is zeroA dynamic name appears with numeric zero.That unmatched name is outside the named-property schemas.The member is allowed without a value constraint.The member is rejected because its name is not listed.The member is rejected because zero does not satisfy a null-only schema.Numeric zero is interchangeable with the null marker.Schema maintainer and application contract ownerPreserve the received payload for diagnosis, then apply the application's stated rejection or migration policy.

Why an open bag can create a marker bug

Consider a hypothetical consumer that treats the presence of any dynamic key as “enabled.” If the producer uses an unrestricted property bag, a false-valued dynamic member can pass that value contract. The consumer could then mistake the key’s presence for an enabled marker. This is a hypothetical design failure, not an observed result.

A proposed correction is to retain the received payload, define null as the only permitted marker value, and validate unmatched members with an additional-properties schema that requires null. Under that contract, false and zero fail the dynamic-value rule before a presence-based consumer can interpret them as markers. Consumers should still read the documented marker convention rather than infer semantics from JSON null itself.

Select the shape that matches the boundary

Choose an unrestricted bag when varied values under varied names are intentionally acceptable and the application has another clear interpretation rule. Choose a null-marker map when names may grow but dynamic values must be limited to one sentinel. Choose a closed fixed-shape object when every accepted name should be declared in advance.

Do not treat a null member as an omitted member. A schema can list properties without making them mandatory; presence is controlled separately through required. If a fixed closed subschema is composed with allOf, names declared only in another subschema can still be treated as additional by that closed subschema, so review that boundary before adopting a composed design.

Limitations and review points

The null-only rule validates a JSON value; it does not itself decide what the marker means to the business domain, who changes the contract, or how an existing false- or zero-based payload is migrated. Those are local policies that should be written beside the schema.

  • Identify which names are fixed and which are legitimately dynamic.
  • State whether a present null marker means selected, requested, enabled, or another local state.
  • Assign ownership for validation errors, migration, and compatibility decisions.
  • Revisit the decision if the source material changes or a version transition affects the deployed schema environment.