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.
| Severity | warn (info for OpenAPI) |
| Kind | Conformance. A finding is a fact about the input. |
| Mode | ax-check lint |
| Applies to | MCP tool lists, OpenAPI |
| Pattern tags | schema-enum, false-success, error-recovery |
| Fix in one line | Set "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
additionalPropertiesset 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.
Related evidence
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.
- EV-0002: Constraints stated only in prose produce silent failures on live APIs (Preprint). SilentProbe (preprint) reports that only 7.5% of 2,501 public OpenAPI documents declare an enum, and that on live endpoints machine-checkable constraints returned an honest error in 111 of 111 cases while prose-only constraints failed silently in 44 of 61.
- EV-0001: An enum in the schema ends silent failures from example-only vocabularies (Preprint). SilentProbe (preprint) reports that a vocabulary a parameter description only exemplified ("e.g.") was missed on 88 of 88 attempts across twelve models, and that promoting it into the schema cut the failure to 0 of 89.
- EV-0004: Naming recovery tools is the active ingredient in failure receipts (Preprint). Outcome Monitors (preprint) reports that receipts naming a violated outcome and the public recovery tools raised ToolMaze completion from 10.9% to 28.1% across four models, and that removing the list of recovery tools eliminated the gain.
- EV-0005: Idempotency keys cut duplicate writes from 28% to 4% (Preprint). LIMBO (preprint) reports that offering an idempotency key on every write cut duplicate side effects from 28% to 4% of episodes because agents use keys when they exist, and that agents reported success in 90% of the episodes in which they had duplicated an effect.
- EV-0003: Error text that names the next tool lifts recovery (Preprint). A preprint testing five OpenAI models reports that an expired-credential error naming a terminal command left 45% of tasks recovered, naming the server's login tool instead raised recovery to 84%, and on rate limits naming the call to repeat raised recovery from 6% to 88%.
- EV-0006: An evidence contract cuts false-success reports after tool failures (Preprint). Failure-Transparent Agents (preprint) reports that after a required tool failed, six models falsely reported success in 22.8% of responses by default, 9.3% with a transparency instruction and 0.8% with a structured evidence contract.
