Payload rejected
HTTP 422 — sanity checks failed
You are getting 422 out_of_range or 422 unknown_kind on ingest. The
sanity checker at the ingest boundary refuses physically implausible
values before they reach storage.
"Out of range"
The ingest endpoint enforces per-kind bounds — see the table on POST /v1/ingest. Common offenders:
- Temperature reported in Kelvin or Fahrenheit. A sensor saying
294(K) is rejected because we treat the value as °C. Convert at the device. - Battery percent vs battery volts mixed. Shelly Gen1 reports
percent; Gen3 reports volts. If your device-side logic sometimes
emits
3.92and sometimes92, the sanity check will trip on the battery channel. - NaN, Infinity, null in JSON. RFC 8259 forbids these as JSON
numbers; we 400 with
bad_json, not 422. Stringify them yourself or drop them. - Pressure in Pa instead of hPa. Standard sea-level pressure is ~1013 hPa = 101 325 Pa. The latter trips the sanity ceiling of 1100. Divide by 100 at the device.
"Unknown kind"
Only the kinds in POST /v1/ingest are accepted. If you have a sensor reporting something exotic (TVOC, PM2.5, soil moisture), you have three options:
- Map to the closest existing kind + use the
labelfield. A soil moisture sensor reporting 0–100 % can usehumiditywithlabel = "soil". The display unit is the same; only the contextual interpretation changes. - Map to a generic numeric kind. We support
voltageandcurrentas the catch-alls for "analog reading"; if your sensor's value can be reasonably expressed as one of these, use it. - Open a ticket. New kinds are added on request; we will not
force a roundabout mapping if your sensor is genuinely a new kind.
So far we have added
co2(2026-04) on request from a school pilot.
"Out of range" but the reading is honest
If the value is physically valid but outside our sanity bounds — e.g. a cryogenic freezer reporting –90 °C, or a power meter on a 100 kW industrial circuit — open a ticket. We will widen the bounds for your account. We do not silently expand them for everyone because the bound exists to catch real device failures (a corroded thermistor reading +200 °C, an ADC bit-flip).
How to handle 422 on the device
Do not retry a 422. The same payload will be rejected again. Log locally, drop the reading, continue with the next cycle. If your device buffers, do not pile up rejected payloads in the buffer; the buffer will fill with garbage and block honest readings.
For ESPHome devices, the recommended pattern is to apply a filter on the sensor before sending:
sensor:
- platform: bme280_i2c
temperature:
filters:
- throttle: 60s
- clamp:
min_value: -40
max_value: 80
Out-of-bounds physical readings become "ignore this cycle" client-side rather than "argue with the server".
Audit trail
A 422 is not recorded in the audit trail — it is rejected before
becoming a measurement. If you need to know that a sensor failed
during a period (for HACCP), look at the per-channel gaps endpoint:
GET /v1/channels/chn_…/gaps?from=…&to=…
A continuous run of 422s shows up as a gap in the data, which is audit-visible.