Build1 distinct publisher3 min readUpdated
A batched track call with no event name is accepted and then dropped before any destination sees it, according to an open source linter's Segment rule pack. The response code will not tell you.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
A collector's job ends at the byte count. Segment's tracking endpoint answers 200 to a batch whose `track` row carries no `event`, and the drop happens after that answer and before any destination [1]. The spec marks `event` as required, the collector takes the call anyway, and it does not invent a name for you [2]. What the 200 asserts is that bytes were received [3]. Anything watching for non-2xx responses therefore has no signal to fire on, and the shortfall only becomes visible wherever events are counted at the far end.
The required-field list is short, which is what makes the silence irritating rather than merely unfortunate. `event` is only required on `track`; `identify`, `page`, `screen`, `group` and `alias` do not need it, so a mixed batch fails only on its track rows [5]. A batch row must carry `type`, and the value has to be one of those six [11] - which means five of the six accepted row types pass the event-name contract by construction, and exactly one can lose data to it [1]. Separately, Segment documents `userId` or `anonymousId` as required on every call, and a track carrying properties and a timestamp but no identity is not associated with anyone: destinations keying on user id see nothing, destinations keying on anonymous id see nothing [7].
The linter's own caveats are the useful part of the writeup. On a single call the type lives in the URL path at `/v1/track` rather than in the body, so a body-level `type` check is scoped to batches and stays quiet on a lone payload [6]. An empty `writeKey` is flagged, a missing one is not, because the key may be travelling as HTTP basic auth in a header that a JSON fixture cannot show [8]. That is the honest boundary of pre-send checking: a fixture is not the wire, and the pack matches Segment payloads by host or by body shape and will lint a fixture with no host at all [13].
Timestamps are where the same mistake stops being portable. Segment documents `timestamp` as an ISO 8601 date string, an epoch number is the wrong type, and for events happening now the advice is to omit the field and let Segment stamp it [9]. PostHog's capture takes the same ISO 8601 shape but reads an epoch value as ingestion time rather than the time you sent; Amplitude wants milliseconds; there is no default timestamp type at this layer [10]. One integer, three outcomes, none of them an error you will see in a response code [2].
Pixellint, whose Segment pack produced these findings, is an open source payload linter and is independent of Segment; the rule ids cite the HTTP API and track spec because that is where the requirements are documented, not because this is an official tool [14]. Read the findings as a reading of Segment's own docs, not as vendor behaviour anyone has certified. The operational point survives either way: the receiver acknowledges receipt and validates nothing, so the check has to happen before the send.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
A server posts a track call to api.segment.io/v1/batch, the response is 200, and downstream destinations never see the event.
Segment's track spec marks `event` as required; the collector still accepts a call that omits it, does not invent a name, and drops the call without it.
Segment's HTTP API is a collector and not a schema checker; the 200 means "we received bytes", and the HTTP 200 is not a contract check.
identify, page, screen, group and alias do not need `event`; the rule is scoped to type: track, so a batch that mixes call types only flags the track rows.
On a single call the type lives in the URL path (/v1/track) rather than the body, so the type enum check is scoped to batch and stays quiet on a lone payload; the event-name check still applies where the body is a batch of tracks.
Segment documents that every call needs userId or anonymousId. A track with properties and a timestamp and no identity is not associated with anyone: destinations that key on user id see nothing, and destinations that key on anonymous id see nothing.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Single self-published source, specific but uncorroborated
The technical detail is unusually concrete for a single-source cluster: named rule ids, exact failing payloads, verbatim linter output, a docs link to Segment's track spec, and explicit scoping caveats about batch-only type checks and header-borne write keys. But every factual load is carried by one dev.to post written by the tool's maintainer; no Segment documentation, changelog, second publisher or third-party test independently confirms the collector's accept-then-drop behaviour, and the PostHog and Amplitude comparisons carry no citation at all.
No usage evidence beyond availability
The post establishes that the Segment pack exists and can be installed via cargo or npm and exercised in a browser playground, but supplies no downloads, stars, users, deployments, CI integrations or third-party accounts. Availability is not adoption, and the sources give no basis to infer usage, so this dimension is left unmeasured rather than estimated.
Slightly overstated headline, restrained body
The framing that a 200 does not mean your event shipped is presented as a general finding, and the failure mode is real as described, yet nothing quantifies how often it bites: there is no incident, no production drop rate and no evidence that teams are widely hitting it. The body is notably disciplined - it narrows rules to track rows, refuses to flag a missing writeKey it cannot verify, and discloses that Pixellint is not an official Segment tool - which keeps the gap small rather than large.
Maintainer promoting own tool, disclosed
The author states outright that they maintain Pixellint, and the post's structure - problem, linter output that catches the problem, install commands, playground link - is a product demonstration. That is a strong commercial or reputational incentive to present the failure mode as pressing. It is partly mitigated by clear disclosure of both authorship and non-affiliation with Segment, and by the fact that the tool is open source with locally executable checks a reader can verify.
Moderate on the mechanism, low on scale
Confidence is reasonable that the described payload contracts and the accept-then-drop behaviour are stated accurately, because the claims are falsifiable, cite a specific spec page, and can be reproduced with the published tool. Confidence is low on everything beyond the mechanism: single publisher, interested author, no corroborating vendor source, no adoption evidence, and uncited third-party vendor behaviour.
build
PostHog capture returns 200 for an epoch timestamp, then dates the event now1 distinct publisher
product
A 2x LLM bill is not a bug report: token spend is an observability problem1 distinct publisher
build
A file-copy Allure adapter for Katalon, and the history IDs that make retries useful1 distinct publisher
build
Block's Berd makes a duller argument than its mascots: show the agent's context as product state1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 21, 2026