Common VAST XML errors and how to fix them
Most VAST ad delivery failures come from the same handful of mistakes. This guide covers the errors that vastlint catches most frequently, with examples and fixes for each.
1. Missing <Impression> element
Every inline VAST ad must contain at least one <Impression> element with a valid URL. Without it, the impression cannot be tracked and most players will discard the tag entirely.
<!-- ❌ Missing Impression -->
<InLine>
<AdTitle>My Ad</AdTitle>
<Creatives>...</Creatives>
</InLine>
<!-- ✅ Fixed -->
<InLine>
<AdTitle>My Ad</AdTitle>
<Impression><![CDATA[https://track.example.com/impression]]></Impression>
<Creatives>...</Creatives>
</InLine>2. Invalid <Duration> format
Duration must follow the HH:MM:SS or HH:MM:SS.mmm format. A bare number like 30 or an ISO 8601 duration like PT30S will fail.
<!-- ❌ Wrong format -->
<Duration>30</Duration>
<Duration>PT30S</Duration>
<!-- ✅ Correct -->
<Duration>00:00:30</Duration>
<Duration>00:00:30.000</Duration>3. Empty or missing <MediaFile>
Inline ads require at least one <MediaFile> element. The URL inside must point to a valid video asset. An empty <MediaFile/> tag or a missing URL causes the ad to fail silently.
4. Malformed tracking URLs
All URIs in <Impression>, <Tracking>, <ClickThrough>, and <MediaFile> must be valid URLs. Common mistakes include missing the protocol (http:// or https://), using spaces, or leaving macros unescaped.
<!-- ❌ Missing protocol -->
<Impression><![CDATA[track.example.com/imp]]></Impression>
<!-- ❌ Unescaped ampersands -->
<Impression><![CDATA[https://track.example.com/imp?a=1&b=2]]></Impression>
<!-- ✅ Correct -->
<Impression><![CDATA[https://track.example.com/imp?a=1&b=2]]></Impression>5. VPAID creatives on CTV / VPAID-blocked environments
VPAID (apiFramework="VPAID") is blocked on most CTV platforms and increasingly on mobile. Serving a VPAID tag where it's unsupported produces no error from the player — the slot just goes dark.
vastlint flags all VPAID tags with an advisory so you can catch them before delivery. The fix is to serve a VAST-native creative (MP4/WebM) and use OMID for measurement instead.
6. Version mismatch
A VAST document declares its version in the root <VAST version="X.X"> attribute. Using elements introduced in VAST 4.x (like <UniversalAdId>) in a tag declared as 3.0, or omitting required 4.x fields, produces version mismatch warnings.
7. Missing <VASTAdTagURI> in wrapper ads
Wrapper ads (type <Wrapper>) must contain a <VASTAdTagURI> pointing to the next tag in the chain. Without it, the player has no way to resolve the wrapper.
8. Duplicate <Impression> URIs
Multiple <Impression> elements are allowed, but they should have different URIs. Identical URIs fire the same pixel twice, inflating impression counts and creating discrepancy alerts.
9. Invalid skipoffset attribute
The skipoffset on <Linear> must be a time offset (HH:MM:SS) or a percentage (50%). Values like 5 (bare number) or skip (string) are invalid.
<!-- ❌ Invalid skipoffset -->
<Linear skipoffset="5">
<!-- ✅ Correct -->
<Linear skipoffset="00:00:05">
<Linear skipoffset="25%">10. No <Ad> element at all
A VAST document with zero <Ad> elements is technically a “no-ad response.” While valid per spec (it signals no fill), an unexpected no-ad response from a tag that should be returning an ad usually indicates a server-side issue.
11. Using HTTP instead of HTTPS
Most players and browsers block mixed content. All media URLs, tracking pixels, and companion assets should use https://. vastlint flags HTTP URLs as advisories.
12. Missing version attribute on <VAST>
The root <VAST> element must have a version attribute. Without it, vastlint cannot determine which spec version to validate against, and most players may treat the tag as invalid or default to inconsistent behavior.
<!-- ❌ Missing version -->
<VAST>
<Ad>...</Ad>
</VAST>
<!-- ✅ Correct -->
<VAST version="4.2">
<Ad>...</Ad>
</VAST>Catch all of these automatically
Every error on this page is one of the 108 rules in vastlint. Paste a tag into the web validator or run vastlint validate tag.xml in your terminal to check all of them instantly.