# Error 400 and 404 – wrong parameters and unknown ids

> Read details in a 400 error, catch misspelled parameters that are ignored without an error, and tell not_found, route_not_found and unknown_entity apart.
>
> https://danadresse.dk/en/guides/fejl-400-og-404 · verified 2026-11-02
A 400 means a parameter has a value the API cannot use. A 404 means the path or the id you ask for does not exist. Both count as a call on your quota, so it pays to catch them in code. The key is checked before the parameters, so if you also have a key problem you see 401 or 403 first.

## 400 invalid_query_parameter

On the DAWA paths a wrong parameter always gives status 400 with `code` `invalid_query_parameter`. `details` is a list with one entry per error:

```json id=bad-param-body run=no
{
  "type": "QueryParameterFormatError",
  "title": "Invalid query parameter",
  "details": [
    {
      "type": "literal_error",
      "loc": ["query", "format"],
      "msg": "Input should be 'json', 'csv', 'geojson', 'geojsonz' or 'ndjson'",
      "input": "xml",
      "ctx": {"expected": "'json', 'csv', 'geojson', 'geojsonz' or 'ndjson'"}
    }
  ],
  "code": "invalid_query_parameter"
}
```

`loc[1]` is the parameter name, `msg` is the reason, and `input` is the value you sent. Write them to your log:

```python id=read-400 run=live expect="invalid_query_parameter"
import os

import requests

r = requests.get(
    "https://api.danadresse.dk/adresser",
    params={"postnr": "8000", "per_side": 5000},
    headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]},
    timeout=10,
)
if r.status_code == 400:
    body = r.json()
    print(r.status_code, body["code"])
    for err in body["details"]:
        print(f"  {err['loc'][-1]} = {err['input']!r}: {err['msg']}")
```

The common causes:

| Symptom in `details` | Cause | Fix |
|---|---|---|
| `per_side`, `less_than_equal` | `per_side` above the limit | At most 1000 on most lists, 100 on `/autocomplete`. See [Pagination](/en/guides/paginering) |
| `side`, `greater_than_equal` | `side=0` | Pages start at 1 |
| `format` or `struktur`, `literal_error` | A value that does not exist | See [Formats](/en/guides/formater-json-csv-geojson) |
| `srid`, `x`, `y`, `int_parsing` or `float_parsing` | Text instead of a number, e.g. a comma as decimal separator | Use a dot: `x=12.5683` |
| `srid`, `value_error`, "srid skal være 4326 (WGS84) eller 25832 (ETRS89/UTM32)" | Another coordinate system, e.g. `srid=3857` | Use `4326` (default) or `25832`. See [Coordinates and srid](/en/guides/koordinater-srid) |
| `x` or `y`, `missing` | Reverse without coordinates | Send both `x` and `y` |
| `entitet`, `missing` | `/replikering/udtraek` without an entity | `?entitet=adresse` |

On `/api/v1` the matching error is `422 validation_error`, and the list is in `error.details`.

### Other 400 codes

| `code` | Cause | Fix |
|---|---|---|
| `invalid_kvh` | `kvh` is not exactly 12 characters | Pad the house number with leading `_`: `03301407___1` |
| `invalid_kvhx` | `kvhx` is not exactly 19 characters | kvh + floor (3) + door (4), padded with `_` |
| `invalid_cirkel` | `cirkel` is not three numbers, or the radius is outside 1-50,000 m | `cirkel=longitude,latitude,radius` |
| `invalid_polygon` | `polygon` is not valid GeoJSON, or has fewer than three points | `polygon=[[[longitude,latitude],…]]`, URL-encoded |
| `invalid_parameter` | `matrikelnr` without `ejerlavkode`, or `husnrfra`/`husnrtil` that is not a house number | `details.parameter` names the parameter. Send `ejerlavkode` too, or a house number such as `5` or `5A` |

## Misspelled parameter names give no error

A parameter name the API does not know is ignored, as it was in DAWA. Known filters do filter, also on `/autocomplete` (`postnr`, `kommunekode`, `adgangsadresseid`) and together with `cirkel`, `polygon` and `medtagnedlagte`. But `?postnummer=8000` does not give an error. It gives the first 100 addresses in the whole country, because the filter was never applied. The same happens with `?kommune=0101` instead of `kommunekode`, `?pr_side=` instead of `per_side`, and `format=csv` on endpoints that only return JSON.

If the result is too broad, check the names against the API description at `/openapi.json`. This function does it automatically before sending the call:

```python id=check-params run=live expect="postnummer"
import os

import requests

API = "https://api.danadresse.dk"
_spec = requests.get(f"{API}/openapi.json", timeout=10).json()


def unknown_params(path: str, params: dict) -> list[str]:
    """Parameter names the endpoint does not know (and would therefore ignore)."""
    known = {p["name"] for p in _spec["paths"][path]["get"].get("parameters", [])}
    return sorted(set(params) - known - {"api_key"})


def checked_get(path: str, params: dict) -> requests.Response:
    bad = unknown_params(path, params)
    if bad:
        raise ValueError(f"Unknown parameters on {path}: {bad}")
    return requests.get(API + path, params=params, timeout=10,
                        headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]})


print("Unknown:", unknown_params("/adresser", {"postnummer": "8000", "per_side": 10}))
r = checked_get("/adresser", {"postnr": "8000", "per_side": 1})
print(r.status_code, r.json()[0]["adressebetegnelse"])
```

Fetch the specification once at startup, not on every call.

## 404 not_found: the id or code does not exist

```json id=not-found-body run=no
{
  "type": "ResourceNotFoundError",
  "title": "Adresse 0a3f507a-ec01-32b8-e044-0003ba298018 not found",
  "details": null,
  "code": "not_found"
}
```

Go through the list:

1. **Access-address id on an address endpoint.** The ids are different. The example above is an access-address id sent to `/adresser/{id}`. Use `/adgangsadresser/{id}`, or `/adresser?adgangsadresseid=…` for the units behind the door. The other way round works: `/adgangsadresser/{id}` with an address id answers with the access address the unit belongs to. See [Adresse or adgangsadresse?](/en/guides/adresse-vs-adgangsadresse)
2. **An id from another system.** An id that does not come from the address register (for example an internal customer id or an id from a test system) does not exist here.
3. **Reverse with no address nearby.** `/adgangsadresser/reverse` gives `404` with `"title": "No address within range"` when there is no address near the point. Usually `x` and `y` are swapped, or UTM coordinates were sent without `srid=25832`. See [Coordinates and srid](/en/guides/koordinater-srid).
4. **Whitespace or a line break in the id.** Strip whitespace before putting the id in the URL.

Codes without leading zeros are not a cause: `/kommuner/101` and `kommunekode=101` work and answer with `0101`. Enrichments under `/api/v1/enrich/adresser/{id}/…` take both an access-address id and an address id.

Try it yourself with an access-address id on the address endpoint:

```bash id=wrong-id-curl run=live expect="not_found"
curl -s "https://api.danadresse.dk/adresser/0a3f507a-ec01-32b8-e044-0003ba298018" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"
```

## 404 route_not_found: the path does not exist

`route_not_found` means the URL does not match any endpoint:

- **`/api/v1` in front of a DAWA path.** The DAWA paths live at the root: `https://api.danadresse.dk/adresser`, not `/api/v1/adresser`.
- **An old path from DAWA's documentation that does not exist here.** See [Compatibility](/kompatibilitet) for the list of supported paths.
- **Typos:** `/adresse` instead of `/adresser`, `/postnummer` instead of `/postnumre`.

The format depends on the path. If it starts with a DAWA path (`/adresser…`), you get the DAWA format. Otherwise you get the `/api/v1` format:

```json id=route-not-found run=no
{
  "detail": {"error": {"code": "route_not_found", "message": "Not Found"}},
  "error": {"code": "route_not_found", "message": "Not Found"}
}
```

## 404 unknown_entity: wrong replication entity

`/replikering/udtraek?entitet=…` and `/replikering/{entitet}/haendelser` know a fixed set of entities. A wrong name gives `unknown_entity`, and `details.supported` lists the ones that work:

```json id=unknown-entity run=no
{
  "type": "ResourceNotFoundError",
  "title": "Unknown replication entity 'adressen'",
  "details": {"supported": ["adgangsadresse", "adresse", "…"], "legacy_names": ["adgangsadresser", "adresser", "…"]},
  "code": "unknown_entity"
}
```

Entities are singular: `adresse`, `adgangsadresse`, `postnummer`. The old plural names such as `adgangsadresser` are accepted too and listed in `details.legacy_names`. See [Replication: events](/en/guides/replikering-haendelser).

## Next steps

- [No results?](/en/guides/ingen-resultater) when the call succeeds but the list is empty.
- [The error format](/en/guides/fejlformat)
- [Adresse or adgangsadresse?](/en/guides/adresse-vs-adgangsadresse)
