Diagnose video ad playback failures (VAST errors)
Reproduce a silent video failure with the placement's VAST tag, read what Epom actually returns on a no-ad, and map common player error codes to the Epom setting that caused them.
A video slot stays blank, the player skips straight to content, or you get a bare “ad error” with no detail. Video players swallow VAST errors — they rarely tell you why, they just move on. This page turns that silence into a diagnosis: reproduce the failure with the placement’s own VAST tag, read what Epom actually returned, and map the player’s error code (if you can get one) to the Epom setting behind it.
This is a video-specific companion to Tags and preview problems, which has the one-line version of this symptom.
First: what Epom returns when nothing serves
Knowing Epom’s actual responses stops you chasing a player bug that is really a “no ad matched”. On a video (VAST) request Epom returns one of:
| Situation | Epom returns | What the player does |
|---|---|---|
| A banner matched | A full <VAST> with the creative’s media/wrapper | Plays the ad |
| A request reached a real placement but no banner matched | A <VAST> with an <Error> element carrying a tracking beacon URL — Epom puts no error code of its own in it, only an [ERRORCODE] slot for the player to fill | Fires the beacon, then reports its own no-ads error (commonly 303) |
| The request had no valid placement (bad key, wrong URL) | An empty <VAST … /> with no <Ad>, at the version the tag asked for (2.0 when the request itself could not be read) | Reports an empty/parse error |
The key takeaway: the error code you see in the player is the player’s, not Epom’s. Epom’s
no-ad response is a valid VAST document whose <Error> fires a beacon so the no-fill is counted;
the player then decides how to surface it. So a “303 No Ads” almost always means Epom found the
placement but had nothing to serve — a selection problem, not a tag problem. Work
My ad is not serving in that case.
Step 1 — reproduce with the placement’s VAST tag
Don’t debug on the live player first. Get a clean signal from the tag itself.
-
Open the video placement → the Ad tags & API card → the VAST tags tab. If your network has more than one ad-serving domain, pick the Domain on the card’s Settings tab first.
-
Pick your player’s spec in the VAST version picker (2.0, 3.0, 4.0, 4.1, 4.2 or 4.3) and copy the VAST tag URL — or copy the VPAID tag or VMAP tag URL, which do not follow the picker. The version rides in the tag’s
vastvparameter where it is visible — on networks that serve encrypted tag URLs it is inside the ciphertext, so read it off the response instead (below). -
Paste it into a VAST validator/inspector (your player vendor’s, or any standalone VAST tester). This shows the raw XML Epom returns for that exact tag, with none of the player’s error-swallowing.
The AI assistant can do this for you: ask it to check the tag URL and it summarises the response — VAST version, each ad as InLine or Wrapper (following wrappers up to three levels), media files with type, size, bitrate and VPAID, and tracking counts — or says there was no ad. Its request comes from a datacenter with a stock desktop, iPhone or Android browser, so a no-ad there can simply be targeting (country, device, IP, frequency) keeping that request out; confirm from a real device before blaming the tag.
What you learn immediately:
- Empty
<VAST/>or a<VAST>…<Error>with only a beacon → no ad matched (or no valid placement). Go to Step 2. - A full
<VAST>with aMediaFileorVASTAdTagURI→ Epom is serving; the failure is playback-side (media, wrapper, VPAID, mime). Go to Step 3.
Corner case: check which VAST version the response actually declares. Read it off the root element —
<VAST version="…">— rather than off the tag URL: the URL’svastv=parameter says the same thing, but on networks that serve encrypted tag URLs the whole query is wrapped into ciphertext and novastvis visible even though the tag carries one. A hand-edited or truncated URL that genuinely has novastv(or an unknown one) is answered with VAST 2.0 for a no-ad response, which can be rejected by a player that expects 4.x features. The picker defaults to 4.2. If the tag also has to be viewability-measured, it must be 4.1 or higher and play in an Open Measurement–capable player — see Video placements.
Step 2: no ad matched, selection side
The tag returns empty or an <Error>-only VAST. Epom reached the placement but had no creative.
Check, most common first:
- No linked, active video banner. A video placement needs a linked banner of a video type (Local Video, External Video, Third Party VAST/VPAID Tag URL, VPAID Framework, Advanced Local Video(s)) that is active, with an active campaign in valid dates/budget. See Video banners.
- The banner’s In-Stream video type is not what the request asks for. The server keeps only banners whose In-Stream video type (Linear / Non-linear) matches the types the tag asks for — a plain VAST tag asks for both, linear first — and drops the rest, which the player sees as a no-ad. This is a selection-side cause, not a player one.
- An uploaded video misses the site’s Video creative requirements. The file stays linked but is not served on that site; the placement’s linked-banners tree marks it Not served. See Check video creatives against a publisher’s spec.
- Targeting / pre-targeting rejected the request. Country, device, time-range and other rules apply to video exactly as to display. Reproduce with the standalone preview’s IP override to test another geo. Behind a server-side ad insertion stitcher the rules see the viewer details the stitcher forwards; one that forwards none shows the rules its own data-centre address (see Serving behind SSAI).
- Capping or limits exhausted. A frequency cap or a spent budget/impression limit removes the only candidate.
- RTB-only demand that didn’t bid. If the placement relies on programmatic video, an empty response is a no-bid, not a bug.
- A pod that comes back shorter than you asked for can be Competitive separation in a pod passing over a creative that clashes with one already in the break — see Keeping competitors apart in a pod.
- The site, zone or placement is switched off. A VAST tag of a paused placement — or of a placement whose site or zone is paused — answers with no ad even though the banner side is fine. Supply needs placement and zone and site on.
- A limit on the placement or site. A Total limit that is reached switches the entity off, and it stays off after you raise the limit — switch it on again yourself (see Limits).
- Site- or zone-level pretargeting. A country rule on the site (or zone) applies to every placement under it — a “VAST returns an error everywhere except from one country” report is usually this. Check the site’s targeting, not only the campaign’s.
Is an empty VAST normal? (fill rate)
Yes, for part of the traffic. Every request the placement cannot fill — no eligible banner, a cap, a no-bid — is answered with the no-ad VAST above, and the player shows its no-ads error for it. A placement filling 15% of its requests answers 85% of them empty by design. Read the share from a General report grouped by placement: Impressions ÷ Requests. Only a fill of zero, or a sudden drop against the same period before, points to a set-up problem — then work the list above. See also Low fill rate.
Confirm it is selection, not tag, in analytics: a General report grouped by placement shows non-zero Requests with zero Impressions for a no-fill. Full checklist: My ad is not serving.
Step 3: Epom served but playback fails
The validator shows real creative markup, yet the live player still fails. The cause is now in the creative or the player, not selection:
- Third-party VPAID tag in a non-VPAID player. A VAST tag that contains a
JavaScriptResource/ VPAID script needs a VPAID-capable player. A plain VAST player renders nothing for it and usually reports a linearity or media error. Confirm the banner is a Third Party VAST/VPAID Tag URL type and that your player supports VPAID. - Wrapper that never resolves. A VAST Tag banner is a wrapper — the player must follow
VASTAdTagURIto the real ad. If the wrapped tag is slow, unreachable, or exceeds the player’s wrapper-depth limit, the player times out. On the banner, the VAST 4.0 Wrapper properties (Follow additional wrappers, Allow multiple ads, Fallback on no ads) control this chain — see Video banners. The depth and time limits themselves are the player’s, not settings on the banner. - Media-file mime/codec the player can’t decode. For Local/External/Advanced Video, the
player needs a
MediaFilewhosetype(mime) and codec it supports. An MP4-only player fed a WebM rendition, or a mismatched declared mime, fails silently. Check the<MediaFile type="…">in the validator against your player’s supported formats. - Ad-pod expectations. If the placement returns a pod (Return (ads in pod) > 1) but the player requested a single ad, or the pod exceeds Max. pod duration, playback can partially fail. Match the placement’s pod settings to what the player asks for.
- Skip settings the player enforces differently. The placement’s Show skip ad button / Show after and the banner’s Show skip button after feed the VAST; a player with its own skip policy may override or conflict with them.
The skip button (skipoffset) is missing from the VAST
Epom writes skipoffset on the <Linear> element only for creatives it serves inline —
Local Video, External Video, Advanced Local Videos and VPAID Framework banners — from the
banner’s Show skip button after (seconds) — or, when the banner has none, the placement’s skip settings — and never in a
VAST 2.0 response, which has no such attribute. A Third Party VAST/VPAID Tag URL banner
is a wrapper: the VAST specification has no skip offset on a wrapper, so the field on such a
banner has no effect. The skip offset has to be in the partner’s own inline VAST, and the
player then shows it.
Pre-roll, mid-roll or post-roll — do I need different VAST tags?
No. A VAST tag does not know where in the content it plays — the player decides when to call it (before, during or after the video). The same placement’s tag can serve pre-roll and mid-roll. If you want the breaks counted separately in reports, use a placement per break (or pass a different channel in each call). A VMAP tag is the exception that describes breaks itself; its Max pre-rolls is set on the video placement — see Video placements.
The ad plays as a separate video on the page, not inside my player
The publisher put the Video Player tag on the page. That tab is a ready-made demo player that renders the placement on its own — it is not a pre-roll for an existing player. For your own player, give it the VAST tag URL (Ad Tags & API → VAST Tags) as its ad tag. The display banner code of another placement is not a VAST tag either; only the video placement’s VAST tag URL returns VAST.
Clicks differ between two players on the same VAST tag
The player decides what is clickable: one player makes the whole video area a link, another
shows only a call-to-action button. Epom counts a click when the player opens the VAST’s
ClickThrough link (or fires its ClickTracking), so the same tag reports more clicks in the
player with the bigger click area. There is no ClickThrough at all when the video banner has
no landing URL.
Reading player error codes (Epom-scoped)
Players report IAB VAST error codes. You don’t need the whole dictionary — these are the ones that map to an Epom-side setting or state:
| Player code (family) | Usually means | Where to look in Epom |
|---|---|---|
| 303 No ads after wrapper(s) | Epom returned a no-ad <Error> VAST | Selection — Step 2 |
| 300–302 Wrapper error, timeout or depth limit | A VAST Tag banner’s wrapped tag is slow or unreachable | Banner VAST 4.0 Wrapper properties, the wrapped tag itself |
| 901 VPAID error / unsupported | VPAID creative in a non-VPAID player | Banner type (VAST/VPAID Tag or VPAID Framework), player capability |
| 400–405 Media-file error | No playable MediaFile, or a codec/mime the player cannot decode | Banner media files, mime types |
| 201 Video player expecting different linearity | The creative is linear and the player wants non-linear, or the reverse | Banner In-Stream video type (Linear / Non-linear) |
| 100 XML parse error | Empty or malformed response reaching the player | Usually the empty <VAST/> case — bad placement key or hand-edited tag |
| 900 Undefined error | The player failed and had no more specific code for it | Work the checklist in What does VAST error 900 mean? |
Note: these ranges are the standard IAB families, but the exact code a player emits varies by player. Treat the code as a pointer to the Epom area, then confirm from the raw XML in Step 1 — the XML is authoritative, the player’s code is a hint.
What does VAST error 900 (Undefined error) mean?
900 is the IAB VAST specification’s “Undefined Error” — the code a video player reports
when playback failed and it cannot name a more specific reason. Epom never produces it: every
<Error> URL Epom writes (on a served ad, on a wrapper and on the no-ad response) ends in
ec=[ERRORCODE], and it is the player that replaces [ERRORCODE] with 900 or any other code.
Google IMA in particular folds many different failures into 900 — a VPAID creative that fails,
a media file it cannot use, a timeout, a request the browser blocked. So a 900 says “the player
gave up”, not where; it needs the same diagnosis as any silent failure.
Check, in this order:
- Does Epom serve at all? Open the placement’s VAST tag in the browser (Step 1). An
<Error>with no<Ad>is a no-fill — work Step 2, the 900 is a consequence. - Does the media file open, and does it suit the player? Copy the
<MediaFile>URL into a browser tab — it must play overhttps. Itstypemust be a format the player decodes (an MP4-only player cannot use WebM), and its size and bitrate must be reasonable for the connection (see How heavy should a banner or video be?). - Is it VPAID? A
MediaFileof typeapplication/javascript(or a VPAID Framework banner) needs a player with VPAID enabled; Google IMA needs VPAID mode switched on by the publisher. A VPAID script that throws inside the player is also reported as a generic failure. - How deep is the wrapper chain? A Third Party VAST/VPAID Tag URL banner is a wrapper; if the partner’s tag wraps again, every hop costs time and each player stops after its own fixed number of hops. Open the partner’s tag yourself and follow it to the inline ad.
- Is anything blocked by the browser? Mixed
httpcontent on anhttpspage, and a media file or VAST hosted on a server that does not allow cross-origin requests (CORS), fail in the player with no detail. Open the browser console and the Network tab on the publisher’s page, play the ad, and look for red requests and CORS errors. - What does the player itself say? IMA, JW Player and Video.js write the underlying error to the console in debug mode; that message is more precise than the 900 the VAST pixel gets.
Where Epom sees the code: when a player fires the
<Error>pixel, the code it filled in is written to the ad server’s troubleshooting log (“Player reported VAST error code 900”) while a capture is running — your network administrator creates a time-boxed task under Admin → Audit & diagnostics → Troubleshooting log tasks and downloads the logs afterwards (see Capture ad requests with a troubleshooting log task). The code is not a column in the reports.
Did the impression fire?
When a video ad does play, verify tracking is landing rather than assuming it from the visible ad:
- The placement’s VAST tracking card lets you enable playback events (start, quartiles, complete, skip, viewability). Enabled events appear in the VAST response as tracking URLs and are recorded when the player fires them — see Video placements.
- In analytics, compare Requests → Impressions first. Requests without impressions = no-fill (Step 2). For playback, group a General report by Conversion action (or Attribution type): the quartile, complete and viewability events are recorded as system conversions, which no longer count in the Conversions column. Impressions without start/quartile events = the player loaded the ad but playback didn’t progress (Step 3 territory — media or player issue).
- A ticked event can be missing from the XML by design. Event names differ by VAST version and Epom leaves out what a version does not define: Ad loaded appears only from 4.1, Exit fullscreen from 3.0, and the linear-video Expand / Collapse are omitted from 4.x (see Video banners). If an enabled event is absent, check the version of the tag first.
- OpenRTB video banners never get Epom’s VAST tracking card — their events come from the bid’s own markup, so absent Epom-side events there is expected, not a bug (see OpenRTB (DSP) banners).
Corner cases and gotchas
Corner case: Epom’s no-ad response is a valid VAST document, not an HTTP error. The request returns
200 text/xmlwith an<Error>beacon inside. A player that only checks the HTTP status will think the call “succeeded” and then fail on the empty ad — look at the body, not the status code.
Corner case: in a VAST 2.0 no-ad response Epom appends
&force_fail=trueto the beacon (inside<Ad><InLine><Error>, because 2.0 has no document-level<Error>). This is expected in the raw XML of a no-ad response — it is not evidence of a forced failure of your creative.
Corner case: a wrapped third-party VAST that itself returns no ad produces a 303 at the player even though Epom served a perfectly valid wrapper. The chain failed downstream of Epom — test the wrapped tag URL directly to confirm.
When you escalate
Give your network administrator: the placement ID, the VAST tag URL you tested and its version, the raw XML the validator showed (or “empty”), the player and its error code, and the time window + reporting time zone. Your network administrator can additionally check gates you can’t see (consent enforcement, bot and IP filtering, DSP creative-scan verdicts), and Epom support the ad-server snapshot state.
Related
- Tags and preview problems
- Video placements
- Video banners
- Video viewability and Open Measurement (OMID) — the ad plays but viewability stays at zero
- My ad is not serving
- OpenRTB (DSP) banners