Skill 104 · Resolving Ingestion Warnings
Subchapter 104.14
references/fixing-person-properties-size-violation.mdMarkdown7 KBView on GitHub
A person-properties update was rejected: applying it would push the person’s stored properties past PostHog’s size limit (on the order of 1MB of JSON).
Category size, severity error: the event itself was ingested, but the $set/$set_once payload it carried was not applied — the person’s profile is now silently stale.
message_size_too_large for the same distinct IDs, it’s the same root cause (load fixing-message-size-too-large).Diagnosing means identifying which growth pattern you’re looking at — each has a different signature and a different fix:
| Pattern | What it looks like | Signature |
|---|---|---|
| Dynamic keying | Keys generated from data: interaction_1042, viewed_2026-07-08, feature_<uuid>_used | Huge key count; each value can be tiny. Size arrives by accumulation — every update adds keys, none ever leave |
| Big payloads | A few monstrous values: a mirrored CRM record, a base64 blob, a full API response, $set_once of a signup snapshot | Normal key count; a handful of keys dominate the value size ranking |
| Deep nesting | A plausible-looking key (settings, metadata, profile) holding a deeply nested object that grows a level or a branch at a time | Neither count nor top-level ranking looks alarming until you open the value — the size hides inside the structure |
These combine: a dynamically-keyed map of nested objects is the worst case and typically comes from “just sync the whole thing” integrations.
posthog:execute-sql: SELECT timestamp, details FROM system.ingestion_warnings WHERE type = 'person_properties_size_violation' AND timestamp > now() - INTERVAL 7 DAY ORDER BY timestamp DESC LIMIT 20. The details JSON carries person_id and distinct_id. Remember distinct IDs are not persons — resolve them (posthog:persons-list filtered by distinct ID); the person’s properties are shared across all of their distinct IDs.JSONExtractKeys(properties) + length() of each value via posthog:execute-sql, or eyeball the person page) — a few dominant keys means big payloads.$set / $set_once / identify / setPersonProperties callsites producing that pattern — key-name templates for dynamic keying, sync jobs for big payloads, incremental merge-into-object logic for nesting.The fix has two parts: a code change so the profile stops growing, and a one-time cleanup of the persons that are already inflated. Both are needed — the code change alone doesn’t unbreak affected persons (their updates keep failing until the stored blob is back under the limit), and cleanup without the code change just buys time until it reoccurs.
Person properties are for current state — bounded facts about the user (plan, role, counts, flags, last-N summaries):
$set a reference (ID/URL) plus the few fields you actually filter on.$unset deletes person data irreversibly, and other things may depend on those properties — cohorts, feature flag conditions, insight filters. Treat it as a remediation the user decides on:
posthog:persons-property-delete does the same job tool-side; for many keys/persons, a one-off script sending $unset:posthog.capture({
distinctId: 'the-affected-user',
event: 'cleanup oversized profile',
properties: { $unset: ['crm_record', 'interaction_history'] },
})$unset takes top-level key names. For dynamic keying, generate the list from the key enumeration in Diagnose. For deep nesting, you can’t unset a nested path — unset the container and re-$set it with its slimmed value.$set (e.g. a profile_cleaned_at timestamp) and confirm it appears on the person — proof updates apply again.system.ingestion_warnings with posthog:execute-sql (filter type = 'person_properties_size_violation', timestamp after your fix) — no new occurrences. Judge by absence of new warnings over a real usage window; historical counts don’t shrink.message_size_too_large was firing for the same persons, confirm it stopped too.