Ingestion warnings
Contents
Sometimes PostHog runs into problems during ingestion due to incorrect or suboptimal usage of PostHog. For example, if you capture an event with a generic ID like null, PostHog doesn't ingest it.
Where we can, we still ingest the event and log an ingestion warning. Other problems leave nothing to ingest, and the warning is the only record. Each section below says whether the event was kept.


Note: These warnings are sampled, so the number of events affected may exceed the total displayed. Use the count to confirm something is happening, not to measure how often.
List of ingestion warnings:
- Refused to merge with an illegal distinct ID
- Refused to merge an already identified user
- Refused to process event with invalid UUID
- Ignored an invalid timestamp, event was still ingested
- An event was sent more than 23 hours in the future
- Discarded event exceeding 1MB limit
- Event ingestion has overflowed capacity
- Skipped person profile processing for a high-volume distinct ID
- Ingested event after shortening its distinct ID to the 200 character limit
- Replay event timestamp is invalid
- Replay event timestamp was too far in the future
- $set or $set_once is ignored on exception events and should not be sent
- Invalid heatmap data
- Discarded $groupidentify event with invalid $group_set
Validation warnings, raised when PostHog rejects a request as it arrives:
- Discarded event with no distinct ID
- Discarded event whose distinct ID exceeds the size limit
- Discarded event with no event name
- Discarded event whose name exceeds the length limit
- Discarded event with an invalid timestamp
- Discarded event with malformed properties
- Discarded event with invalid capture options
- Rejected batches
- Discarded session replay batches
- Discarded AI events
Refused to merge with an illegal distinct ID
See our identify docs for what happens when you call identify or alias with an illegal distinct ID like guest or null.
Refused to merge an already identified user
See our identify docs for details on how we handle duplicate users.
Refused to process event with invalid UUID
PostHog drops events with invalid UUIDs.
There are very few cases where it would be good to provide an event UUID. PostHog generates these for you.
When generating UUIDs, there are many gotchas to be aware of. For example, deduping based on event UUID is not guaranteed due to how merges work in ClickHouse.
Ignored an invalid timestamp, event was still ingested
When capturing events, the timestamp and sent_at fields should be in ISO 8601 format. When parsing fails, PostHog ignores these fields and computes them itself as if omitted. These events are still ingested, but their timestamp might differ from the one you intended.
An event was sent more than 23 hours in the future
This warning indicates a bug in your instrumentation, as we don't expect events from the future. Read about how we compute event timestamps and review your instrumentation code (the sent_at or the offset values might be wrong).
These events are ingested and stored, but will not show up in the UI. If these events create new persons, these persons will have a "first seen" property in the future.
Discarded event exceeding 1MB limit
PostHog discards events exceeding 1 megabyte in size after processing. The two common ways this happens are:
An event is captured with an exceptionally large number of properties (including person properties)
One or more installed apps transformed the event and enriched it with a large amount of additional property data.
Event ingestion has overflowed capacity
This warning indicates PostHog is receiving more events for a single distinct_id than it can process in the main ingestion pipeline. These events are still safe and ingested but through a slower overflow pipeline. This is often a sign of an instrumentation bug such as a loop sending the same event.
Skipped person profile processing for a high-volume distinct ID
One distinct ID sent events much faster than expected, so PostHog skipped person processing for those events. The events are still ingested. They just don't create or update a person profile while the limit is active.
This usually means one distinct ID is shared by many users or machines. See rate limiting high-volume distinct IDs for how to fix it.
Ingested event after shortening its distinct ID to the 200 character limit
PostHog shortens any distinct_id longer than 200 characters to its first 200 characters and ingests the event under the shortened ID. The same limit applies to session replay events, which are ingested under the shortened ID without a warning.
A distinct ID this long usually means something other than a user ID, like a token or a serialized object, was passed as the distinct ID. Fix the capture or identify call to send a real user ID. Until then, events keep landing under the shortened ID.
Replay event timestamp is invalid
The replay event timestamp is not valid and the session replay event is dropped.
Replay event timestamp was too far in the future
The replay event timestamp is more than 7 days in the future and the session replay event is dropped.
Invalid set operations on exception events
The $set or $set_once properties are ignored on exception events and should not be sent.
Invalid heatmap data
PostHog couldn't process the $heatmap_data attached to an event, so no heatmap data was extracted from it. The event itself is still ingested as normal.
This indicates the $heatmap_data property was malformed, which is usually a sign of an instrumentation bug. If you're capturing heatmap data with posthog-js, make sure you're on a recent version of the SDK and aren't manually constructing or modifying $heatmap_data yourself.
Discarded $groupidentify event with invalid $group_set
PostHog discards $groupidentify events when the $group_set property is not a valid JSON object. The $group_set property must be a plain object containing the group properties you want to set — strings, numbers, booleans, and arrays are rejected.
To fix this, ensure $group_set is always a plain object when calling posthog.group() or sending $groupidentify events:
null or undefined values for $group_set are accepted and upsert the group with empty properties.
Validation warnings
These warnings are raised when PostHog rejects a request as it arrives, before the event enters the ingestion pipeline. Your SDK receives an HTTP 400 naming the problem, for example event submitted without a distinct_id. Requests are validated as a unit, so one malformed event can reject the whole batch — which is why a warning's event count can exceed the number of warnings.
Rejected events are dropped, and the warning is the only record of them: details carry identifiers and sizes (the SDK name and version, the endpoint, and an occurrence count) rather than event contents. To inspect a rejected payload, capture it at the sender — look for 400 responses to your capture host in your browser's network tab, enable debug mode with posthog.debug(), or log the event in a before_send hook.
Start with the lib and lib_version details. Warnings clustered on a single older SDK version point to an upgrade. When both read unknown, the request carried no $lib property, which typically means traffic from outside a PostHog SDK — project API keys are public, so bots and scanners can generate these warnings independently of your code.
Discarded event with no distinct ID
Every event needs a distinct_id to attribute it to a person. PostHog reads the top-level distinct_id first, then falls back to properties.distinct_id, and drops the event when neither holds a usable value — when it's missing from both, null, empty, or only whitespace.
PostHog accepts a wide range of values here: numbers and objects are converted to strings, and literal strings like "null", "undefined", and "anonymous" are valid IDs. Prefer real user IDs — placeholder values group unrelated users onto a single person, and merging them later raises cannot_merge_with_illegal_distinct_id.
The usual cause is an empty variable at the capture() call site:
- The ID passed to
capture()oridentify()isundefinedornullbecause it hasn't loaded yet. Identify once your auth state resolves. - A
before_sendhook, reverse proxy, or middleware layer removesdistinct_idon the way out. bootstrap.distinctIDcomes from another system (a server-rendered page or a native app handover) and is sometimesnull. Passbootstraponly when you have an ID: anullis stored as-is, so that browser keeps sending unattributable events until its storage is cleared. OmittingdistinctIDor passing an empty string is safe — posthog-js generates an anonymous ID instead.
Validate the ID before capturing:
Discarded event whose distinct ID exceeds the size limit
The distinct_id was longer than 200 characters. An ID this long is usually something else — a token, a session blob, or a serialized object — so update the capture or identify call to send a real user ID.
Some capture endpoints shorten the ID and ingest the event instead. See Ingested event after shortening its distinct ID.
Discarded event with no event name
The event field was missing or empty, so there was no name to record the event under. The usual cause is an empty variable at the capture() call site.
Discarded event whose name exceeds the length limit
The event name was longer than 200 characters. Use short, stable identifiers like user_signed_up, and move any variable data (an ID, a URL, a message) into a property. This also keeps your event list easy to browse.
Discarded event with an invalid timestamp
The event's timestamp couldn't be parsed. Send timestamps in ISO 8601 format.
Some endpoints keep the event and substitute the server's time instead — see Ignored an invalid timestamp. Which applies depends on the endpoint your SDK uses.
Discarded event with malformed properties
The properties field wasn't a JSON object — commonly an array or a string. This most often means the properties were JSON-encoded twice, so check for a stray JSON.stringify() before the value reaches capture().
Discarded event with invalid capture options
The request's capture options were malformed. SDKs set these for you, so this points to a hand-built HTTP request — check it against the capture API reference.
Rejected batches
These warnings apply to a whole request rather than a single event, so every event in the request is dropped together.
| Warning | Cause |
|---|---|
| Rejected a request containing no events | The request body contained an empty batch, typically from a client that flushes on a timer with nothing queued. |
| Rejected a batch with invalid metadata | The batch's envelope (the fields wrapping the events) was malformed. |
| Rejected a batch containing an event with no UUID | An event in the batch was missing its UUID. |
| Rejected a batch containing an event with an invalid UUID | An event's UUID wasn't valid. PostHog generates these for you — see Refused to process event with invalid UUID. |
| Rejected a batch containing duplicate event UUIDs | Two events in the batch shared a UUID, usually from a retry or queue flush re-sending events. |
Discarded session replay batches
These warnings mean a chunk of a session recording was dropped. The recording still exists, minus the part that chunk covered, so it may appear shorter than expected. All three usually point to an outdated SDK or a proxy that rewrites request bodies.
| Warning | Cause |
|---|---|
Discarded a session replay batch with no $session_id | The batch didn't identify which session it belonged to. |
Discarded a session replay batch with an invalid $session_id | The $session_id was present but unusable — most often not a string. |
Discarded a session replay batch with no $snapshot_data | The batch carried no recording data. |
Discarded AI events
These warnings apply to LLM analytics events.
| Warning | Cause |
|---|---|
Discarded an AI event with an unsupported event name or no $ai_model | The event wasn't a recognized $ai_* event, or the required $ai_model property was missing. |
| Rejected a malformed AI or OpenTelemetry request | The request body couldn't be parsed. |
| Accepted an OpenTelemetry export with no AI spans, so nothing was ingested | The export was valid but carried no AI spans. Check that your instrumentation is emitting them. |
Query warnings via MCP
If you use the PostHog MCP server, your AI agent can query ingestion warnings directly with the ingestion-warnings-list tool. Ask questions like "What ingestion warnings has my project received?" or "Why are my person merges failing?" and the agent will filter, search, and summarize warnings for you. See the MCP tools reference for the full list of available tools.