# invalid_request

A handler refused a request it could read but cannot act on (400).

## Meaning

The request passed the schema check and a handler still refused it. The causes:
- a hosted sign-in UI call (`/v1/auth/*`, or `/orgs/{slug}/v1/auth/*`) sent without
  a body, or a registration or emailed-link request without a usable email address;
- an admin API call (`/v1/admin/*`) that breaks a rule of its own, such as a create
  user body with both or neither of `password` and `invite`, a blank `username`, an
  audit filter that does not parse, or a list cursor that was altered or belongs to
  another sort or collection;
- a consent or logout confirmation for an authorization or logout request the
  server cannot find or no longer accepts;
- on any route, middleware before the handler: one of `Authorization`, `DPoP`,
  `DPoP-Nonce`, `Cookie`, `Origin`, `Sec-Fetch-Site` or `Content-Type` repeated.

## Impact

The request did nothing. A user of the hosted sign-in UI sees an error on the form or
an error page; it usually means the page and the server disagree, a stale tab, or a
proxy that rewrote the request. For an admin-API caller or a client developer it is
a bug in the caller. It is not expected in normal operation.

## Diagnosis

1. Read `detail`: for a handler refusal it names the rule, such as
   "send exactly one of password and invite".
2. Look the `request_id` (also in `X-Request-ID`) up on the admin dashboard's
   Troubleshooting page, or with the `request_id` filter of
   `GET /v1/admin/orgs/{slug}/audit-events`. A repeated header is recorded as
   `http.header.repeated` with reason `repeated_header` and the header's name in
   `header`; a refused cursor names `cursor_tampered`, `cursor_scope_mismatch` or
   `cursor_sort_mismatch` as its cause.
3. For a repeated header, compare what the client sent with what reached the server:
   a proxy that appends its own `Cookie` or `Authorization` line causes it.

## Mitigation

- As a user: reload the sign-in page from the application and try again.
- As a client or admin-API developer: fix the request as `detail` says. Send each
  single-valued header once, start a list again without the cursor instead of
  editing one, and do not retry the same request unchanged.
- As an operator: if every request through one proxy is refused for a repeated
  header, configure the proxy to replace the header rather than add a second one.

## Escalation

Escalate when a request the documentation says is valid is refused, or when the
hosted sign-in UI shipped with the server triggers it on its own. Open an issue with
the request id, the `detail`, the endpoint and the server version
(`nauthera-server version`). Never attach tokens, cookies or passwords.

---

[Problem code runbooks](https://www.nauthera.io/docs/v1/runbooks/problems) · Generated from [`internal/runbook/problems.yaml`](https://github.com/nauthera/nauthera-server/blob/main/internal/runbook/problems.yaml) in nauthera-server.
