skip to content

On OpenRouter, what happens to request parameters the chosen model doesn't support?

level: middleimportance: must knowfreq 55%

answer

  1. Compatibility is per model, not per gateway
  2. No 400 for a field it cannot use
  3. Silence, not failure, is the hazard
  4. Ask the catalog before you send
  5. GET /api/v1/models lists supported parameters

basics

~20 s

By default they are dropped, not rejected: OpenRouter forwards only the parameters the target model honours and returns a normal completion. The danger is silence — your setting simply had no effect, so verify support against the model catalog instead of assuming.

solid answer

~50 s

OpenRouter accepts the full OpenAI-style parameter set on every model, but the models behind it differ in what they actually implement. Rather than failing a request because, say, a given model has no `top_k` or no `response_format`, the gateway strips the parameters that model does not support and sends the rest. You get a 200 and a plausible-looking answer that quietly ignored your instruction — which is far more dangerous than a 400, because nothing in the response says a field was dropped. The fix is to look before you send: `GET /api/v1/models` lists each slug together with the request parameters it honours and the input modalities it accepts, so you can assert support at startup or when the model id is chosen. Note this is about *unsupported* fields; a malformed value on a field the model does support is still a validation error.

code

bash · 4 lines
bash
curl -s https://openrouter.ai/api/v1/models \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  | jq '.data[] | select(.id == "anthropic/claude-sonnet-4.5")
        | {id, context_length, supported_parameters}'

go deeper

for a junior

Remember the headline: unsupported parameters are dropped, not rejected, so a request can succeed while quietly ignoring what you asked for. Know that the models endpoint tells you what each model accepts.

for a middle

Explain why drop-by-default exists — it is what keeps a model swap to a one-string change — and give a concrete failure it causes, such as JSON mode being stripped and a parser breaking downstream.

for a senior

Show how you'd stop it reaching production: validate capabilities at startup from the catalog, branch on capability rather than model name, and validate model output rather than trusting a parameter was honoured.

for a principal

Own the abstraction's cost. Decide which parameters are load-bearing for the product, make those a hard requirement in model qualification, and treat any model that lacks them as ineligible rather than papering over it in application code.

## The compatibility surface is not flat OpenRouter's promise is one request shape for hundreds of models. That promise cannot mean every model implements every field, because the models genuinely differ: some expose `top_k`, some do not; some support JSON-schema-constrained output, some only free-form text; some accept images, most do not; some accept tool definitions, some ignore them; reasoning-oriented models may fix their own sampling and disregard `temperature` entirely. So the gateway has to choose a policy for the mismatch, and its default policy is **drop, do not fail**. Parameters the target model does not support are removed from the upstream call, and the request proceeds. ## Why silent dropping is the right default and the wrong surprise It is the right default because it is what makes model swapping a one-string change. If every unsupported field 400'd, moving from one slug to another would break code that was written against the first model's capabilities, and the whole abstraction would leak on day one. It is a surprise because nothing in the HTTP status tells you. Consider an app that relies on `response_format` to get parseable JSON. Point it at a model that does not implement structured output and you do not get an error — you get prose with a JSON-ish blob in the middle, or a fenced code block, or an apology. Your parser fails downstream, far from the cause. The same shape of bug appears with a `seed` you thought made runs reproducible, a `stop` sequence that never truncates, or a `logit_bias` that changes nothing. ## Check the catalog `GET /api/v1/models` returns the machine-readable catalog. Each entry carries the model's slug, its context length, the modalities it accepts and produces, and the list of request parameters it supports. That last field is exactly the contract you want to assert against. Two useful patterns: 1. **Startup validation.** When a model id comes from configuration, fetch its catalog entry once at boot and fail fast if a parameter your code depends on is missing. A crash on deploy beats mystery output in production. 2. **Capability-driven code paths.** If your app supports several models, branch on capability rather than on the slug string: if structured output is available use it, otherwise fall back to prompt-and-validate with a retry. Branching on names rots the moment a new model is added. ## Unsupported field versus invalid value Keep the two apart. Dropping applies to *fields the model does not implement*. If you send a field the model does support but with a value outside its accepted range or of the wrong type, that is a validation error and you should expect a 4xx rather than a silent fix-up. Similarly, sending image content to a text-only model is not a parameter drop — it is content the model cannot consume, and that fails visibly. ## Normalisation the other way Dropping is only half the job. For the parameters a model *does* support, the gateway also maps them onto the vendor's own names and semantics, so the OpenAI spelling you sent reaches the upstream in whatever form it expects. And the response is normalised back: the same `choices[].message` structure and the same finish-reason vocabulary, regardless of which vendor answered. Normalisation is not lossless, and the reason to know the drop policy is precisely to know where the loss can hide. ## Defensive practice Always validate the *output*, not just the request. If you need JSON, parse it and retry on failure rather than trusting that a parameter was honoured. Log which model actually served each call, so when output shape changes you can correlate it with a model change. And when you add a new slug to your rotation, diff its supported parameters against the one it replaces before shipping — most "the gateway broke my app" incidents are really "the new model never supported the field I depended on".

  • How would you find out in advance whether a model on OpenRouter accepts tools or images?
    Query `GET /api/v1/models` and read that slug's entry: it lists the request parameters the model honours and the input modalities it accepts, so tool support and image support are both visible without sending a probe request. Bake that check into startup validation when the model comes from configuration, so an unsupported capability fails the deploy instead of degrading output silently at runtime.
  • Your app depends on JSON output. What is the risk of the drop policy, and how do you defend?
    If the model does not implement structured output the field is stripped, the call returns 200, and you get prose your parser chokes on. Defend at two layers: assert the capability against the catalog before selecting the model, and always validate the returned payload — parse it, and on failure retry with a stricter prompt or fall back to a model that does support constrained output.
  • Is a rejected parameter value the same thing as an unsupported parameter?
    No. An unsupported parameter is one the model does not implement, and the gateway removes it so the call can proceed. An out-of-range or wrongly typed value on a parameter the model does implement is a malformed request and should surface as a client error. The first is silent by design; the second is loud by design, and conflating them leads people to expect errors that never arrive.

saying these in an interview costs you the question

  • Expecting a 400 whenever a model lacks a parameter
  • Assuming every slug honours temperature and top_p identically
  • Trusting response_format without validating the output
  • Hardcoding capabilities per model name instead of querying
  • Believing OpenAI compatibility means feature parity everywhere

context