ax-check rule

AXC-D012: Object schema does not set additionalProperties to false

An input object lists its properties but leaves additionalProperties unset, so a misspelt argument is silently accepted.

ax-check is a checker being prepared for release. This page documents the rule ahead of that release; see all 50 rules.

Severitywarn (info for OpenAPI)
KindConformance. A finding is a fact about the input.
Modeax-check lint
Applies toMCP tool lists, OpenAPI
Pattern tagsschema-enum, false-success, error-recovery
Fix in one lineSet "additionalProperties": false on input objects whose properties are a closed set.

An input object lists its properties but leaves additionalProperties unset, so it still accepts unknown ones. If an agent misspells an argument, sending dueDate instead of due_date, the value is silently ignored. The call succeeds, the default is used, and the agent reports success for something it did not do.

What it checks

ax-check walks the input schema of each tool or operation and reports every object that defines properties but says nothing about other keys.

Why it matters

Agents make small naming mistakes: camelCase for snake_case, a plural for a singular, a field from a different tool. A closed schema turns each of these into an honest error that names the bad key, and the agent can correct itself on the next turn. An open schema hides the mistake.

Li, Ye, Guo and Dang measured the difference between constraints a machine can check and constraints written only in prose. The paper’s claim (SilentProbe, August 2026) is that machine-checkable constraints gave an honest error in 111 of 111 cases, while prose-only constraints failed silently in 44 of 61. additionalProperties: false is the machine-checkable way to say “these are the only arguments”. The paper tested constraints on API parameters, not additionalProperties on tool inputs, so applying its result here is design rationale. See also Agent error recovery: design the path back.

Public HTTP APIs sometimes accept unknown fields on purpose, so that old clients keep working as the API grows. That is why the finding is info for OpenAPI and a warning for MCP tools, where the schema is written for one caller: the model.

How to fix

Set "additionalProperties": false on input objects whose properties are a closed set, including nested objects. If the schema is built with allOf, closing each part breaks the combination; use "unevaluatedProperties": false on the outer schema instead (JSON Schema 2020-12, which OpenAPI 3.1 uses). Make sure the server enforces the same rule and returns an error that names the unknown key.

Example

Before

"inputSchema": {
  "type": "object",
  "properties": {
    "invoice_id": { "type": "string", "description": "ID of the invoice to change." },
    "due_date": { "type": "string", "format": "date", "description": "New due date (UTC)." },
    "billing_address": {
      "type": "object",
      "description": "New billing address. Omit it to keep the current one.",
      "properties": {
        "line1": { "type": "string" },
        "postcode": { "type": "string" }
      }
    }
  },
  "required": ["invoice_id"]
}

After

"inputSchema": {
  "type": "object",
  "properties": {
    "invoice_id": { "type": "string", "description": "ID of the invoice to change." },
    "due_date": { "type": "string", "format": "date", "description": "New due date (UTC)." },
    "billing_address": {
      "type": "object",
      "description": "New billing address. Omit it to keep the current one.",
      "properties": {
        "line1": { "type": "string", "description": "First line of the street address." },
        "postcode": { "type": "string", "description": "Postal code, as the customer writes it." }
      },
      "additionalProperties": false
    }
  },
  "required": ["invoice_id"],
  "additionalProperties": false
}

How ax-check detects it

The rule reads the MCP inputSchema and, for OpenAPI, the schema of the first JSON media type in the request body. OpenAPI path and query parameters are not objects and are not checked.

A schema counts as an object when type is object, or when it has no type but has properties. It is reported when it has at least one property, additionalProperties is not set at all, unevaluatedProperties is not false and patternProperties is absent. Setting additionalProperties to true or to a schema is treated as a deliberate choice to accept extra keys, and is not reported. ax-check then descends into properties that are objects and into arrays of objects, up to five levels deep, and reports each open object with its own pointer.

Known false negatives: objects inside allOf, oneOf or anyOf branches, and objects behind a $ref deeper than the direct properties, are not inspected. An additionalProperties: true added by a code generator, rather than chosen by a person, is not reported either.

Known false positives: an object that is meant to be open but does not say so is reported. If extra keys are intended, say so with additionalProperties: true or a schema for the extra values, which also documents the choice. If the server already rejects unknown keys, the schema is under-describing it: add additionalProperties: false. Otherwise use --disable AXC-D012.

Sources

  • Paper: Li, Ye, Guo and Dang, “SilentProbe: Measuring Silent Failure in Production APIs Used as Agent Tools”, arXiv 2609.00035, submitted 29 August 2026 (preprint, not peer reviewed). https://arxiv.org/abs/2609.00035 . The paper’s claim is that machine-checkable constraints gave an honest error in 111 of 111 cases and prose-only constraints failed silently in 44 of 61.
  • Site guide: Write tool descriptions an agent can act on, agentexperience.tech. https://agentexperience.tech/insights/tool-descriptions/ . Asks for closed sets in the schema as an enum, with additionalProperties set to false.
  • Specification: OpenAPI Specification 3.1.0, OpenAPI Initiative. https://spec.openapis.org/oas/v3.1.0 . The version of OpenAPI whose schemas follow JSON Schema 2020-12, including unevaluatedProperties.

Records in the AX evidence register that share a pattern tag with this rule. A shared tag means the record is about the same pattern, not that it tests this rule. Read the evidence class before the number.