ax-check rule
AXC-D018: Required property not defined
The schema marks a property as required but never defines it, or the required list is malformed.
ax-check is a checker being prepared for release. This page documents the rule ahead of that release; see all 50 rules.
| Severity | error |
| Kind | Conformance. A finding is a fact about the input. |
| Mode | ax-check lint |
| Applies to | MCP tool lists, OpenAPI |
| Pattern tags | schema-enum, error-recovery |
| Fix in one line | Define every required property under "properties", or remove it from "required". |
The input schema marks a property as required but never defines it, or its required list is malformed. In a closed schema, a required property that is not defined cannot be sent at all, so no call can ever be valid. An agent that follows the schema gets an error it has no way to fix.
What it checks
For each MCP tool’s inputSchema and each OpenAPI operation’s JSON request body schema, ax-check checks the top-level required keyword:
requiredmust be an array. A value such as"required": trueor"required": "email"is reported.- Every entry in the array must be a string. A number or object in the list is reported.
- No property may be listed twice.
- In a closed schema (
"additionalProperties": false), every required property must appear underproperties.
These checks mirror four checks in the audit_agent_path tool on agentexperience.tech: catalog.malformed_required_array, catalog.malformed_required_entry, catalog.duplicate_required_property and catalog.required_property_not_defined.
Why it matters
An agent builds its arguments from the schema. When the schema requires customer_id but properties only defines customerId, and unknown properties are rejected, the agent has two choices and both fail: leave customer_id out and break the required rule, or send it and break the closed object rule. The agent sees an error that it cannot recover from by reading the schema again.
Malformed required values are a common leftover from other schema dialects, where required: true sat on each property. Different validators may handle these values differently, so the same tool can behave one way in one client and another way in the next.
How to fix
- Define every required property under
properties, with the exact same spelling. - Or remove the name from
requiredif callers should not send it. - Make
requiredan array of unique strings, or remove it when nothing is required.
Example
Before
{
"name": "create_invoice",
"inputSchema": {
"type": "object",
"properties": {
"customerId": { "type": "string", "description": "The customer's ID, for example cus_123." },
"amount": { "type": "number", "description": "Total in the invoice currency." }
},
"required": ["customer_id", "amount", "amount"],
"additionalProperties": false
}
}
After
{
"name": "create_invoice",
"inputSchema": {
"type": "object",
"properties": {
"customer_id": { "type": "string", "description": "The customer's ID, for example cus_123." },
"amount": { "type": "number", "description": "Total in the invoice currency." }
},
"required": ["customer_id", "amount"],
"additionalProperties": false
}
}
How ax-check detects it
ax-check reads the top-level required keyword of the input schema and reports each problem at its exact position (for example /tools/0/inputSchema/required/0).
A required property that is missing from properties is reported only when the schema is closed: additionalProperties is false and the schema uses none of $ref, oneOf, anyOf, allOf, not, if, then, else, patternProperties or a list of types, either at the top level or directly on a property. One exception: a top-level anyOf whose branches only list required (the usual way to say “send at least one of these fields”) is allowed. In an open schema, the property may still be allowed through additionalProperties, a pattern or composition, so this is not a proven contradiction. Like the agentexperience.tech audit, ax-check does not report a required property that is missing from an open schema. (The audit lists that case as inconclusive; ax-check stays silent.)
Known false negatives:
- Only the top-level input schema is checked. A
requiredlist inside a nested object is not. - For OpenAPI, only the JSON request body schema is checked. The
requiredflag on path, query and header parameters is a separate field and is not part of this rule. - Open schemas are never reported for missing properties, as described above.
If the finding does not apply, silence it with --disable AXC-D018.
Sources
- Specification: Model Context Protocol, Tools, revision 2026-07-28. https://modelcontextprotocol.io/specification/2026-07-28/server/tools. A tool’s
inputSchemais the JSON Schema clients use to build and check arguments. - Specification: OpenAPI Specification v3.1.0, OpenAPI Initiative, 15 February 2021. https://spec.openapis.org/oas/v3.1.0. Request bodies are described with JSON Schema objects.
- Guide: Write tool descriptions an agent can act on, agentexperience.tech, retrieved 2026-10-08. https://agentexperience.tech/insights/tool-descriptions/. Put closed sets in the schema and set
additionalPropertiesto false. - Related check: the agentexperience.tech
audit_agent_pathtool reports the same defects ascatalog.malformed_required_array,catalog.malformed_required_entry,catalog.duplicate_required_propertyandcatalog.required_property_not_defined.
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-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-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.
