CustomLabs
Reliability & guardrails

How do you stop a model from calling a tool with an argument it invented?

Updated First published

5 min read

Markdown

Intent

Every tool argument is defined by a strict JSON schema: enums for known value sets, validated patterns for IDs, required fields where genuinely needed. There is no free-text catch-all surface. A call that fails validation is rejected with a structured, actionable error the model can act on, never silently coerced or passed through to execution.

Also known as schema-validated tools, strict tool schemas, validate-reject-repair

Problem

What problem does this solve?#

A tool schema that accepts any string for an ID field, and marks every field optional, never forces the model to justify where a value came from. It can generate a plausible-looking ID from pattern alone, the same way it would complete plausible code. If the schema does not distinguish that from a value that actually came from a prior lookup, both look identical to the calling code.

If the server also skips validating that a generated value corresponds to something real before acting on it, a fabricated argument sails through to execution unchecked. This is a schema and validation gap more than a model-quality gap. A model asked to fill an unconstrained field will complete the pattern it was trained to produce, and a plausible-shaped ID is exactly that pattern.

Mechanics

How does it work?#

Every tool argument gets the tightest schema the domain allows: a known enum where the value set is small and fixed, a validated regex pattern where it is not. `required` gets marked accurately, rather than defaulting everything to optional. Free-text fields are reserved for genuinely free-text content, such as a message body, never for identifiers or structured values a lookup could supply instead.

The server validates every call against its schema before executing anything. It treats validation failure as a distinct, measured category from execution failure, not lumped into one generic error bucket. A validation failure returns a structured, specific reason, such as "no matching record for X," the model can act on, rather than a silent no-op or a generic 500.

Where practical, mutating tools accept only IDs that trace back to a value returned by an earlier read or lookup call in the same run. That check is enforced at the orchestration layer, not left to the model's discretion. So an argument the model wrote from scratch, rather than copied from real data, cannot reach anything that changes state.

Shape

What are the moving parts?#

  1. Constrain every ID/enum field to the tightest schema available

    Use an enum or a validated pattern, never a bare free-form string, wherever the domain allows it.

  2. Mark fields required based on actual need

    Set required accurately instead of defaulting every field to optional.

  3. Validate every call server-side before execution

    Treat validation failure as a category distinct from execution failure.

  4. Return a structured, specific error on validation failure

    Give the model something it can act on, not a silent no-op or a generic error.

  5. Give the agent a lookup tool instead of expecting recall

    Let it search for a real ID rather than infer or remember one from context.

  6. Trace mutating arguments back to a prior read result

    Enforce, where practical, that a value passed to a mutating tool came from an earlier lookup in the same run, not from scratch.

Fit

When does it fit, and when doesn't it?#

Use it when

  • Tool calls fail at a rate noticeably above expected legitimate user error, especially with plausible-shaped but nonexistent IDs
  • Any tool in the agent's reach can mutate state, such as write, delete, send, or refund, rather than only read
  • The agent is expected to reference existing records by ID across multiple turns
  • You're onboarding a new tool and want its contract to fail safely from day one rather than after an incident

Don't use it when

  • The tool is genuinely read-only, low-stakes, and idempotent (e.g. a public search) where a bad argument just returns an empty result with no downstream harm
  • The value space is inherently open-ended free text (a user's message, a search query). Forcing an enum or pattern there breaks the tool's actual purpose
  • You're validating something the caller already validated one layer up, and duplicating it buys nothing but latency. Check whether the guarantee already holds before adding a redundant layer
Trade-offs

What does it actually cost?#

Gain

Fabricated IDs get rejected before they reach anything real

Cost

Tighter schemas take real domain modeling work up front. You have to know the actual enum or pattern rather than accept anything

Gain

Validation failures become a measured, distinct metric instead of hiding inside a generic error rate

Cost

More rejected calls in the short term, as legitimate edge cases the schema didn't anticipate get caught too. Expect a tuning period

Gain

A model given a lookup tool stops needing to recall or infer IDs at all

Cost

An extra tool call (the lookup) on every task that references an existing record, adding a step and some latency

Gain

Tracing mutating arguments back to a prior read call closes off invented IDs at the orchestration layer, beyond the schema layer

Cost

That tracing has to be built and maintained in the harness itself. It's not something a schema alone can enforce

Signals

How do you know it's working?#

  • Tool call rejection rate, split explicitly into validation failures vs. execution failures
  • Rate of rejected calls where the invalid argument does not appear in any prior tool result the agent received
  • HallucinationA hallucination is a confident, fluent output that is factually wrong or unsupported. rate on free-form ID fields vs. enum/pattern-constrained ID fields, compared directly
  • Share of mutating-tool calls whose argument traces to a prior read-tool result
Prevents

What failure modes does this prevent?#

Sources

  1. JSON Schema - JSON Schema, Draft 2020-12

    The schema specification a tool description must satisfy under our rule bank. Retrieved 2026-08-24.

  2. Model Context Protocol - MCP Specification: Tools (2026-07-28)

    The specification text our tool-design and catalogue rules are checked against. Retrieved 2026-08-24.

Not sure this is the right pattern?

A Ship Audit checks which of these patterns your system actually needs, prioritized against what's most likely to break first.

Book a Ship Audit

Source: https://customlabs.io/patterns/typed-tool-contract/

navigate select esc close