A seller-side agent finishes a video deal and posts back VAST XML. The HTTP status is 200. The root carries a <Ad> with a wrapper chain and a sibling <Error> whose CDATA points at a no-fill beacon. Trafficking tools that only check well-formed XML accept it. SSAI and players built for VAST 4.0 were told to treat the root as one of two shapes, not both.
I see this most often when an agentic pipeline merges patterns from two eras: pre-4.0 examples that habitually included a root <Error> for empty inventory, and 4.x responses that still carry an <Ad> because the buy cleared upstream. IAB Tech Lab's AAMP stack and AdCP both land on the same delivery artifact, a VAST tag, and neither layer rewrites the XML before the player sees it. The comparison of those stacks is in AAMP vs AdCP on agentic advertising; the gap this post cares about is structural, not which SDK initiated the hop.
What the root is supposed to mean
From VAST 4.0 onward, the <VAST> element is modeled as a choice at the root: either one or more <Ad> elements, or a single <Error> element signaling no ad is available. You do not get both in one valid document. The prose is explicit because players need a single interpretation: is this a fill with creatives, or a no-fill with an error URL to ping?
VAST 2.x culture encouraged always shipping an <Error> node so measurement could record why a slot went empty. That habit collides with 4.0's choice model when a partial fill still returns an ad. The result looks like defensive XML, but it is invalid for the version declared on the tag.
vastlint flags this as VAST-4.0-wrapper-root-error: the root contains both <Ad> and <Error>. It is a warning tied to IAB VAST 4.0 section 2.1, not a generic "malformed XML" message. The fix is operational: pick one story. Either remove the root <Error> and rely on wrapper or inline error handling inside the ad, or drop the <Ad> nodes and emit a pure no-fill response with <Error> only.
<VAST version="4.2" xmlns="http://www.iab.com/VAST">
<Ad id="agent-1">
<Wrapper>
<AdSystem version="1.0">Example</AdSystem>
<VASTAdTagURI><![CDATA[https://example.com/next]]></VASTAdTagURI>
</Wrapper>
</Ad>
<Error><![CDATA[https://track.example.com/vast-error]]></Error>
</VAST>
That document is easy for an LLM or template engine to produce. It is also exactly the combination the 4.0 schema choice rejects.
Empty <Ad> shells are a different hole
Another agent failure mode sits one level down: an <Ad> element with neither <InLine> nor <Wrapper>. The root can look busy while every ad slot is hollow. Rule VAST-2.0-ad-has-inline-or-wrapper fires because each <Ad> must contain exactly one of those two children. Agentic buyers can mark a creative "delivered" when the manifest and deal objects agree, while nobody opened the tag to see an empty <Ad id="1"></Ad>. That is a different bug from the root Error mix, but it shows up in the same MCP validation pass.
How you catch it before the player
Do not wait for underdelivery reports. Paste the live tag URL or the XML into the VAST tag tester. It fetches the response, shows the parsed tree, and runs the version-aware rule set so a 4.2 declaration is checked against 4.x root rules, not against 2.0 habits.
When the seller returns a wrapper, open the VAST inspector on the same URL. It walks the wrapper chain hop by hop. A root-level Error beside the first Ad often means the agent never resolved whether the chain terminates in an InLine with media. You want that answer before the stitcher blocks on the cue point.
For CI or pre-commit checks on files agents generate, the validate page accepts pasted XML and returns the same rule ids. Wire that through the agentic integration guide if you already expose vastlint as an MCP tool inside an AAMP buyer or seller agent: the RPC can succeed while the payload still carries a root choice violation.
Where to read the rules
The root choice violation is documented on VAST-4.0-wrapper-root-error. Hollow ads are on VAST-2.0-ad-has-inline-or-wrapper. For how spec-level checks differ from platform quirks (IMA, GAM, player-specific behavior), start with the IAB VAST validator guide.
vastlint is independent of IAB Tech Lab. It checks malformed or inconsistent payloads; it does not score fraud or viewability. The point for agentic buying is narrower: deal state and HTTP success are not proof that the VAST root tells a story players can execute.
Top comments (0)