<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Aleksander Sekowski</title>
    <description>The latest articles on Forem by Aleksander Sekowski (@aleksuix).</description>
    <link>https://forem.com/aleksuix</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3866734%2F559a0a69-3c28-49e2-91c7-503810b941ba.png</url>
      <title>Forem: Aleksander Sekowski</title>
      <link>https://forem.com/aleksuix</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aleksuix"/>
    <language>en</language>
    <item>
      <title>How vastlint's Validation Rules Were Extracted from the VAST PDF Specs and XSD Schemas</title>
      <dc:creator>Aleksander Sekowski</dc:creator>
      <pubDate>Fri, 01 May 2026 15:39:18 +0000</pubDate>
      <link>https://forem.com/aleksuix/how-vastlints-validation-rules-were-extracted-from-the-vast-pdf-specs-and-xsd-schemas-5b1</link>
      <guid>https://forem.com/aleksuix/how-vastlints-validation-rules-were-extracted-from-the-vast-pdf-specs-and-xsd-schemas-5b1</guid>
      <description>&lt;p&gt;The IAB Tech Lab publishes VAST as two artifacts: a PDF specification document and a set of XSD schema files. The PDF is the normative authority. It defines what a conformant VAST response must, should, and may contain. The XSD describes the document structure in machine-readable form but has gaps; it does not cover business logic, ordering constraints, or anything involving URLs. Building a linter against VAST meant reading both and treating them as complementary sources of truth, not interchangeable ones.&lt;/p&gt;

&lt;p&gt;The PDF extraction was manual and slow. Each version of the spec (2.0, 3.0, 4.0, 4.1, 4.2, 4.3) was read cover to cover and every normative statement was tagged by element, attribute, and constraint type. A rule like "InLine must contain AdTitle" comes directly from section language in the 2.0 spec that predates all subsequent versions and has never been relaxed. Deprecations were tracked version by version: conditionalAd deprecated in 4.1, Survey deprecated in 4.1, the fullscreen/exitFullscreen tracking events removed in 4.0. Each one becomes a versioned rule rather than a blanket error, so a VAST 3.0 document is not penalised for things that only matter in 4.x.&lt;/p&gt;

&lt;p&gt;The XSD pass was more systematic. The schemas enumerate valid attribute values, allowed child elements, and content models for every element across spec versions. These became structural rules: unknown attributes, unknown child elements, invalid enum values for things like delivery, adType, renderingMode, and tracking event names. A third category of rules does not come from either the PDF or the XSD. It comes from what goes wrong in production. HTTPS enforcement on MediaFile and tracking URLs, duplicate Impression URLs causing billing disputes, missing quartile tracking events, the VPAID-in-CTV footgun: these are rules sourced from patterns that show up repeatedly in real VAST traffic. The source tag on each rule (VastSpec, VastXsd, IndustryBestPractice, Inferred, etc.) reflects exactly where it came from.&lt;/p&gt;

&lt;p&gt;The full rule set is listed below. Each rule ID links to its dedicated page on vastlint.org with the exact spec section, severity, fix guidance, and examples.&lt;/p&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule ID&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-root-element/" rel="noopener noreferrer"&gt;VAST-2.0-root-element&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Root element must be &lt;code&gt;&amp;lt;VAST&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-root-version/" rel="noopener noreferrer"&gt;VAST-2.0-root-version&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;VAST&amp;gt;&lt;/code&gt; must have a version attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-root-version-value/" rel="noopener noreferrer"&gt;VAST-2.0-root-version-value&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;VAST version attribute must be a recognised version string&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-root-has-ad-or-error/" rel="noopener noreferrer"&gt;VAST-2.0-root-has-ad-or-error&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;VAST&amp;gt;&lt;/code&gt; must contain at least one &lt;code&gt;&amp;lt;Ad&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;Error&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-wrapper-root-error/" rel="noopener noreferrer"&gt;VAST-4.0-wrapper-root-error&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;VAST&amp;gt;&lt;/code&gt; root contains both &lt;code&gt;&amp;lt;Ad&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Error&amp;gt;&lt;/code&gt; elements (invalid per VAST 4.0)&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-ad-has-inline-or-wrapper/" rel="noopener noreferrer"&gt;VAST-2.0-ad-has-inline-or-wrapper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Each &lt;code&gt;&amp;lt;Ad&amp;gt;&lt;/code&gt; must contain exactly one &lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-inline-adsystem/" rel="noopener noreferrer"&gt;VAST-2.0-inline-adsystem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;AdSystem&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-inline-adtitle/" rel="noopener noreferrer"&gt;VAST-2.0-inline-adtitle&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;AdTitle&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-inline-impression/" rel="noopener noreferrer"&gt;VAST-2.0-inline-impression&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; must contain at least one &lt;code&gt;&amp;lt;Impression&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-inline-creatives/" rel="noopener noreferrer"&gt;VAST-2.0-inline-creatives&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;Creatives&amp;gt;&lt;/code&gt; with at least one &lt;code&gt;&amp;lt;Creative&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-adservingid-present/" rel="noopener noreferrer"&gt;VAST-4.1-adservingid-present&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;AdServingId&amp;gt;&lt;/code&gt; (VAST 4.1+)&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-universaladid-present/" rel="noopener noreferrer"&gt;VAST-4.0-universaladid-present&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Creative&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;UniversalAdId&amp;gt;&lt;/code&gt; (VAST 4.0+)&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-universaladid-idregistry/" rel="noopener noreferrer"&gt;VAST-4.0-universaladid-idregistry&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;UniversalAdId&amp;gt;&lt;/code&gt; must have an idRegistry attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-universaladid-idvalue/" rel="noopener noreferrer"&gt;VAST-4.0-universaladid-idvalue&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;UniversalAdId&amp;gt;&lt;/code&gt; missing required idValue attribute (VAST 4.0)&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-universaladid-idvalue-removed/" rel="noopener noreferrer"&gt;VAST-4.1-universaladid-idvalue-removed&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;UniversalAdId&amp;gt;&lt;/code&gt; idValue attribute was removed in VAST 4.1&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-universaladid-content/" rel="noopener noreferrer"&gt;VAST-4.1-universaladid-content&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;UniversalAdId&amp;gt;&lt;/code&gt; must have text content in VAST 4.1+&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-linear-duration/" rel="noopener noreferrer"&gt;VAST-2.0-linear-duration&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Linear&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;Duration&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-linear-mediafiles/" rel="noopener noreferrer"&gt;VAST-2.0-linear-mediafiles&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Linear&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;MediaFiles&amp;gt;&lt;/code&gt; with at least one &lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-mediafile-delivery/" rel="noopener noreferrer"&gt;VAST-2.0-mediafile-delivery&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; must have a delivery attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-mediafile-delivery-enum/" rel="noopener noreferrer"&gt;VAST-2.0-mediafile-delivery-enum&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; delivery must be "progressive" or "streaming"&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-mediafile-type/" rel="noopener noreferrer"&gt;VAST-2.0-mediafile-type&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; must have a type attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-mediafile-dimensions/" rel="noopener noreferrer"&gt;VAST-2.0-mediafile-dimensions&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; must have width and height attributes&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-wrapper-adsystem/" rel="noopener noreferrer"&gt;VAST-2.0-wrapper-adsystem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;AdSystem&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-wrapper-impression/" rel="noopener noreferrer"&gt;VAST-2.0-wrapper-impression&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt; must contain at least one &lt;code&gt;&amp;lt;Impression&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-wrapper-vastadtaguri/" rel="noopener noreferrer"&gt;VAST-2.0-wrapper-vastadtaguri&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;VASTAdTagURI&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-companion-resource/" rel="noopener noreferrer"&gt;VAST-2.0-companion-resource&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Companion&amp;gt;&lt;/code&gt; must contain at least one StaticResource, IFrameResource, or HTMLResource&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-nonlinear-resource/" rel="noopener noreferrer"&gt;VAST-2.0-nonlinear-resource&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;InLine &lt;code&gt;&amp;lt;NonLinear&amp;gt;&lt;/code&gt; must contain at least one StaticResource, IFrameResource, or HTMLResource&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-wrapper-depth/" rel="noopener noreferrer"&gt;VAST-2.0-wrapper-depth&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Wrapper chain depth exceeds the configured maximum&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-ad-sequence/" rel="noopener noreferrer"&gt;VAST-2.0-ad-sequence&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Mixed use of sequence attribute across &lt;code&gt;&amp;lt;Ad&amp;gt;&lt;/code&gt; elements in a pod&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-duration-format/" rel="noopener noreferrer"&gt;VAST-2.0-duration-format&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Duration&amp;gt;&lt;/code&gt; value does not match HH:MM:SS[.mmm] format&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-text-only-element/" rel="noopener noreferrer"&gt;VAST-2.0-text-only-element&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Text-only element contains a child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-unknown-attribute/" rel="noopener noreferrer"&gt;VAST-2.0-unknown-attribute&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Element has an attribute not defined in the VAST spec&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-inline-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-inline-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-wrapper-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-wrapper-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-creatives-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-creatives-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Creatives&amp;gt;&lt;/code&gt; may only contain &lt;code&gt;&amp;lt;Creative&amp;gt;&lt;/code&gt; elements&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-creative-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-creative-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Creative&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-linear-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-linear-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Linear&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-trackingevents-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-trackingevents-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;TrackingEvents&amp;gt;&lt;/code&gt; may only contain &lt;code&gt;&amp;lt;Tracking&amp;gt;&lt;/code&gt; elements&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-mediafiles-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-mediafiles-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFiles&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-extensions-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-extensions-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Extensions&amp;gt;&lt;/code&gt; may only contain &lt;code&gt;&amp;lt;Extension&amp;gt;&lt;/code&gt; elements&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-videoclicks-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-videoclicks-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;VideoClicks&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-nonlinearads-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-nonlinearads-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;NonLinearAds&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-nonlinear-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-nonlinear-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;NonLinear&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-companionads-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-companionads-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;CompanionAds&amp;gt;&lt;/code&gt; may only contain &lt;code&gt;&amp;lt;Companion&amp;gt;&lt;/code&gt; elements&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-companion-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-companion-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Companion&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-creativeextensions-unknown-child/" rel="noopener noreferrer"&gt;VAST-2.0-creativeextensions-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;CreativeExtensions&amp;gt;&lt;/code&gt; may only contain &lt;code&gt;&amp;lt;CreativeExtension&amp;gt;&lt;/code&gt; elements&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-extension-misplaced-element/" rel="noopener noreferrer"&gt;VAST-2.0-extension-misplaced-element&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Extension&amp;gt;&lt;/code&gt; contains an element that has a dedicated location in the VAST spec&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-creative-extension-misplaced-element/" rel="noopener noreferrer"&gt;VAST-2.0-creative-extension-misplaced-element&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;CreativeExtension&amp;gt;&lt;/code&gt; contains an element that has a dedicated location in the VAST spec&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-mediafile-https/" rel="noopener noreferrer"&gt;VAST-2.0-mediafile-https&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; URL uses HTTP instead of HTTPS, blocked by mixed-content policy on secure inventory&lt;/td&gt;
&lt;td&gt;Industry Best Practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-tracking-https/" rel="noopener noreferrer"&gt;VAST-2.0-tracking-https&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Tracking or click URL uses HTTP instead of HTTPS, blocked by mixed-content policy, measurement signal lost&lt;/td&gt;
&lt;td&gt;Industry Best Practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-url-empty/" rel="noopener noreferrer"&gt;VAST-2.0-url-empty&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;URL field is empty&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-url-invalid/" rel="noopener noreferrer"&gt;VAST-2.0-url-invalid&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;URL field does not appear to be a valid URI&lt;/td&gt;
&lt;td&gt;RFC 3986&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-parse-error/" rel="noopener noreferrer"&gt;VAST-2.0-parse-error&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;XML parse error, document may be malformed&lt;/td&gt;
&lt;td&gt;XML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-version-mismatch/" rel="noopener noreferrer"&gt;VAST-2.0-version-mismatch&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Declared version does not match structural signals&lt;/td&gt;
&lt;td&gt;Inferred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-duplicate-impression/" rel="noopener noreferrer"&gt;VAST-2.0-duplicate-impression&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Duplicate &lt;code&gt;&amp;lt;Impression&amp;gt;&lt;/code&gt; URL within the same &lt;code&gt;&amp;lt;Ad&amp;gt;&lt;/code&gt;, causes double-counted billing and disputes&lt;/td&gt;
&lt;td&gt;Industry Best Practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-nonlinear-dimensions/" rel="noopener noreferrer"&gt;VAST-2.0-nonlinear-dimensions&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;NonLinear&amp;gt;&lt;/code&gt; missing width or height&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-companion-dimensions/" rel="noopener noreferrer"&gt;VAST-2.0-companion-dimensions&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Companion&amp;gt;&lt;/code&gt; missing width or height&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-flash-mediafile/" rel="noopener noreferrer"&gt;VAST-2.0-flash-mediafile&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Flash-based MediaFile type is no longer supported&lt;/td&gt;
&lt;td&gt;Inferred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-2.0-linear-tracking-quartiles/" rel="noopener noreferrer"&gt;VAST-2.0-linear-tracking-quartiles&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Linear&amp;gt;&lt;/code&gt; has no standard quartile tracking events, impression serves but measurement system receives no signal&lt;/td&gt;
&lt;td&gt;Industry Best Practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icons-unknown-child/" rel="noopener noreferrer"&gt;VAST-3.0-icons-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icons&amp;gt;&lt;/code&gt; may only contain &lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; elements&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-unknown-child/" rel="noopener noreferrer"&gt;VAST-3.0-icon-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-iconclicks-unknown-child/" rel="noopener noreferrer"&gt;VAST-3.0-iconclicks-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;IconClicks&amp;gt;&lt;/code&gt; contains an unrecognised child element&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-progress-offset/" rel="noopener noreferrer"&gt;VAST-3.0-progress-offset&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Tracking event="progress"&amp;gt;&lt;/code&gt; requires an offset attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-progress-offset-format/" rel="noopener noreferrer"&gt;VAST-3.0-progress-offset-format&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Tracking progress offset does not match required format&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-attrs/" rel="noopener noreferrer"&gt;VAST-3.0-icon-attrs&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Icon missing recommended attributes (program/width/height/position)&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-program/" rel="noopener noreferrer"&gt;VAST-3.0-icon-program&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; missing required program attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-width/" rel="noopener noreferrer"&gt;VAST-3.0-icon-width&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; missing required width attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-height/" rel="noopener noreferrer"&gt;VAST-3.0-icon-height&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; missing required height attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-xposition/" rel="noopener noreferrer"&gt;VAST-3.0-icon-xposition&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; missing required xPosition attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-yposition/" rel="noopener noreferrer"&gt;VAST-3.0-icon-yposition&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; missing required yPosition attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-icon-resource/" rel="noopener noreferrer"&gt;VAST-3.0-icon-resource&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Icon&amp;gt;&lt;/code&gt; must have at least one resource element&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-skipoffset-format/" rel="noopener noreferrer"&gt;VAST-3.0-skipoffset-format&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Linear skipoffset does not match HH:MM:SS[.mmm] or n% format&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-skip-event-no-skipoffset/" rel="noopener noreferrer"&gt;VAST-3.0-skip-event-no-skipoffset&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;skip tracking event present but Linear has no skipoffset attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-minmaxbitrate-pair/" rel="noopener noreferrer"&gt;VAST-3.0-minmaxbitrate-pair&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; must have both minBitrate and maxBitrate or neither&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-bitrate-conflict/" rel="noopener noreferrer"&gt;VAST-3.0-bitrate-conflict&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; has both bitrate and minBitrate/maxBitrate&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-pricing-model/" rel="noopener noreferrer"&gt;VAST-3.0-pricing-model&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Pricing&amp;gt;&lt;/code&gt; missing required model attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-pricing-currency/" rel="noopener noreferrer"&gt;VAST-3.0-pricing-currency&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Pricing&amp;gt;&lt;/code&gt; missing required currency attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-pricing-model-case/" rel="noopener noreferrer"&gt;VAST-3.0-pricing-model-case&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Pricing&amp;gt;&lt;/code&gt; model value should be lowercase in VAST 3.0 (cpm/cpc/cpe/cpv)&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-pricing-currency-format/" rel="noopener noreferrer"&gt;VAST-3.0-pricing-currency-format&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Pricing&amp;gt;&lt;/code&gt; currency attribute must be a 3-letter ISO-4217 code&lt;/td&gt;
&lt;td&gt;ISO 4217&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-3.0-companion-required-attr/" rel="noopener noreferrer"&gt;VAST-3.0-companion-required-attr&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;CompanionAds&amp;gt;&lt;/code&gt; required attribute must be all, any, or none&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-conditionalad/" rel="noopener noreferrer"&gt;VAST-4.0-conditionalad&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;conditionalAd attribute is deprecated as of VAST 4.1&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-wrapper-clickthrough/" rel="noopener noreferrer"&gt;VAST-4.0-wrapper-clickthrough&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;ClickThrough&amp;gt;&lt;/code&gt; inside Wrapper &lt;code&gt;&amp;lt;VideoClicks&amp;gt;&lt;/code&gt; was removed in VAST 4.0 (re-allowed in 4.2)&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-tracking-event-removed/" rel="noopener noreferrer"&gt;VAST-4.0-tracking-event-removed&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;fullscreen/exitFullscreen tracking events were removed in VAST 4.0&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-mediafile-apiframework/" rel="noopener noreferrer"&gt;VAST-4.0-mediafile-apiframework&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFile apiFramework&amp;gt;&lt;/code&gt; is deprecated in VAST 4.0+, use &lt;code&gt;&amp;lt;InteractiveCreativeFile&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-category-authority/" rel="noopener noreferrer"&gt;VAST-4.0-category-authority&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Category&amp;gt;&lt;/code&gt; missing required authority attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-companion-clicktracking-id/" rel="noopener noreferrer"&gt;VAST-4.0-companion-clicktracking-id&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;CompanionClickTracking&amp;gt;&lt;/code&gt; missing required id attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.0-interactive-creative-no-api/" rel="noopener noreferrer"&gt;VAST-4.0-interactive-creative-no-api&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InteractiveCreativeFile&amp;gt;&lt;/code&gt; should have an apiFramework attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-adservingid-present/" rel="noopener noreferrer"&gt;VAST-4.1-adservingid-present&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InLine&amp;gt;&lt;/code&gt; must contain &lt;code&gt;&amp;lt;AdServingId&amp;gt;&lt;/code&gt; (VAST 4.1+)&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-ad-serving-id-empty/" rel="noopener noreferrer"&gt;VAST-4.1-ad-serving-id-empty&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;AdServingId&amp;gt;&lt;/code&gt; is present but empty&lt;/td&gt;
&lt;td&gt;Inferred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-survey-deprecated/" rel="noopener noreferrer"&gt;VAST-4.1-survey-deprecated&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Survey&amp;gt;&lt;/code&gt; is deprecated as of VAST 4.1&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-vpaid-apiframework/" rel="noopener noreferrer"&gt;VAST-4.1-vpaid-apiframework&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;apiFramework="VPAID" is deprecated as of VAST 4.1&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-mezzanine-delivery/" rel="noopener noreferrer"&gt;VAST-4.1-mezzanine-delivery&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Mezzanine&amp;gt;&lt;/code&gt; missing required delivery attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-mezzanine-type/" rel="noopener noreferrer"&gt;VAST-4.1-mezzanine-type&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Mezzanine&amp;gt;&lt;/code&gt; missing required type attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-mezzanine-width/" rel="noopener noreferrer"&gt;VAST-4.1-mezzanine-width&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Mezzanine&amp;gt;&lt;/code&gt; missing required width attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-mezzanine-height/" rel="noopener noreferrer"&gt;VAST-4.1-mezzanine-height&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Mezzanine&amp;gt;&lt;/code&gt; missing required height attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-mezzanine-recommended/" rel="noopener noreferrer"&gt;VAST-4.1-mezzanine-recommended&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;MediaFiles&amp;gt;&lt;/code&gt; has no &lt;code&gt;&amp;lt;Mezzanine&amp;gt;&lt;/code&gt;, ad-stitching servers may reject in CTV/SSAI contexts&lt;/td&gt;
&lt;td&gt;Industry Best Practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-verification-no-resource/" rel="noopener noreferrer"&gt;VAST-4.1-verification-no-resource&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Verification&amp;gt;&lt;/code&gt; should have JavaScriptResource or ExecutableResource&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-verification-vendor/" rel="noopener noreferrer"&gt;VAST-4.1-verification-vendor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;Verification&amp;gt;&lt;/code&gt; is missing required vendor attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-blockedadcategories-no-authority/" rel="noopener noreferrer"&gt;VAST-4.1-blockedadcategories-no-authority&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;BlockedAdCategories&amp;gt;&lt;/code&gt; should have authority attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-interactive-creative-type/" rel="noopener noreferrer"&gt;VAST-4.1-interactive-creative-type&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InteractiveCreativeFile&amp;gt;&lt;/code&gt; should have a type attribute identifying the MIME type&lt;/td&gt;
&lt;td&gt;IANA Media Types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-js-resource-apiframework/" rel="noopener noreferrer"&gt;VAST-4.1-js-resource-apiframework&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;JavaScriptResource&amp;gt;&lt;/code&gt; is missing required apiFramework attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-exec-resource-apiframework/" rel="noopener noreferrer"&gt;VAST-4.1-exec-resource-apiframework&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;ExecutableResource&amp;gt;&lt;/code&gt; is missing required apiFramework attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-exec-resource-type/" rel="noopener noreferrer"&gt;VAST-4.1-exec-resource-type&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;ExecutableResource&amp;gt;&lt;/code&gt; is missing required type attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-tracking-event-value/" rel="noopener noreferrer"&gt;VAST-4.1-tracking-event-value&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Tracking event attribute not in the valid set for this VAST version&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-adtype-value/" rel="noopener noreferrer"&gt;VAST-4.1-adtype-value&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ad adType must be video, audio, or hybrid&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-companion-renderingmode-value/" rel="noopener noreferrer"&gt;VAST-4.1-companion-renderingmode-value&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Companion renderingMode must be default, end-card, or concurrent&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.1-vpaid-in-interactive-context/" rel="noopener noreferrer"&gt;VAST-4.1-vpaid-in-interactive-context&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;VPAID MediaFile alongside InteractiveCreativeFile, VPAID unsupported in CTV, zero fill&lt;/td&gt;
&lt;td&gt;Industry Best Practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.2-closedcaptionfiles-unknown-child/" rel="noopener noreferrer"&gt;VAST-4.2-closedcaptionfiles-unknown-child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;ClosedCaptionFiles&amp;gt;&lt;/code&gt; may only contain &lt;code&gt;&amp;lt;ClosedCaptionFile&amp;gt;&lt;/code&gt; elements&lt;/td&gt;
&lt;td&gt;VAST XSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.2-icon-fallback-image-width-height/" rel="noopener noreferrer"&gt;VAST-4.2-icon-fallback-image-width-height&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;IconClickFallbackImage&amp;gt;&lt;/code&gt; should have width and height attributes&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/rules/VAST-4.3-js-resource-browser-optional/" rel="noopener noreferrer"&gt;VAST-4.3-js-resource-browser-optional&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;JavaScriptResource&amp;gt;&lt;/code&gt; should have a browserOptional attribute&lt;/td&gt;
&lt;td&gt;VAST Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.0-simid-type-required/" rel="noopener noreferrer"&gt;SIMID-1.0-simid-type-required&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InteractiveCreativeFile apiFramework="SIMID"&amp;gt;&lt;/code&gt; must have type="text/html"&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.0-simid-url-empty/" rel="noopener noreferrer"&gt;SIMID-1.0-simid-url-empty&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InteractiveCreativeFile apiFramework="SIMID"&amp;gt;&lt;/code&gt; must contain a non-empty URL&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.0-simid-url-https/" rel="noopener noreferrer"&gt;SIMID-1.0-simid-url-https&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InteractiveCreativeFile apiFramework="SIMID"&amp;gt;&lt;/code&gt; URL must use HTTPS&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.0-simid-variable-duration-value/" rel="noopener noreferrer"&gt;SIMID-1.0-simid-variable-duration-value&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;InteractiveCreativeFile&amp;gt;&lt;/code&gt; variableDuration attribute must be "true" when present&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.0-simid-mediafile-required/" rel="noopener noreferrer"&gt;SIMID-1.0-simid-mediafile-required&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Linear SIMID ad must include a video/audio &lt;code&gt;&amp;lt;MediaFile&amp;gt;&lt;/code&gt; alongside the interactive creative&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.1-nonlinear-simid-no-iframe/" rel="noopener noreferrer"&gt;SIMID-1.1-nonlinear-simid-no-iframe&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;NonLinear apiFramework="SIMID"&amp;gt;&lt;/code&gt; must contain an &lt;code&gt;&amp;lt;IFrameResource&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.1-iframe-simid-type-required/" rel="noopener noreferrer"&gt;SIMID-1.1-iframe-simid-type-required&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;IFrameResource&amp;gt;&lt;/code&gt; in SIMID &lt;code&gt;&amp;lt;NonLinear&amp;gt;&lt;/code&gt; should have type="text/html"&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.1-iframe-simid-url-empty/" rel="noopener noreferrer"&gt;SIMID-1.1-iframe-simid-url-empty&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;IFrameResource&amp;gt;&lt;/code&gt; in SIMID &lt;code&gt;&amp;lt;NonLinear&amp;gt;&lt;/code&gt; must contain a non-empty URL&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vastlint.org/docs/simid-rules/SIMID-1.1-iframe-simid-url-https/" rel="noopener noreferrer"&gt;SIMID-1.1-iframe-simid-url-https&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;IFrameResource&amp;gt;&lt;/code&gt; in SIMID &lt;code&gt;&amp;lt;NonLinear&amp;gt;&lt;/code&gt; URL must use HTTPS&lt;/td&gt;
&lt;td&gt;SIMID Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>adtech</category>
      <category>opensource</category>
      <category>rust</category>
    </item>
    <item>
      <title>I Built a VS Code Extension That Validates VAST XML as You Type</title>
      <dc:creator>Aleksander Sekowski</dc:creator>
      <pubDate>Mon, 20 Apr 2026 04:13:48 +0000</pubDate>
      <link>https://forem.com/aleksuix/i-built-a-vs-code-extension-that-validates-vast-xml-as-you-type-2ln</link>
      <guid>https://forem.com/aleksuix/i-built-a-vs-code-extension-that-validates-vast-xml-as-you-type-2ln</guid>
      <description>&lt;p&gt;If you work in ad tech you've probably seen VAST XML. It's the IAB standard that carries every video and CTV ad impression: the tag that tells a player what to show, where to fire tracking pixels, and how to handle wrappers. $30B+ in annual US ad spend runs through it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw258f958f7g4cw5ps19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw258f958f7g4cw5ps19.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's also surprisingly easy to ship a broken one. The spec is six versions deep (2.0 through 4.3), touches several other standards (XML, RFC 3986, IANA media types, ISO 4217), and the tooling for validating it has historically been: read the PDF, or find out from your partner's discrepancy report.&lt;/p&gt;

&lt;p&gt;So I built vastlint, an open-source VAST linter with 108 rules written in Rust. Last week I shipped the VS Code extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Install it from the VS Code Marketplace. Open any .xml file that contains a VAST tag.&lt;/p&gt;

&lt;p&gt;You get squiggles on the exact element or attribute that violates the spec, hover tooltips with the rule ID and the fix, and Problems panel integration with file path and line number. VAST version is auto-detected. No config, no CLI, no external service. The validator runs entirely in-process via WebAssembly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually catches
&lt;/h2&gt;

&lt;p&gt;Here's a broken tag in the editor. This one is missing  on the  element, a required field since VAST 2.0 that's easy to drop when templating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Linear&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Duration is required — VAST-2.0-linear-duration --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MediaFiles&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;MediaFile&lt;/span&gt; &lt;span class="na"&gt;delivery=&lt;/span&gt;&lt;span class="s"&gt;"progressive"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/mp4"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"640"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"360"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;![CDATA[https://example.com/video.mp4]]&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/MediaFile&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/MediaFiles&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Linear&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The squiggle lands on . Hovering shows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VAST-2.0-linear-duration · Error
&amp;lt;Linear&amp;gt; is missing required &amp;lt;Duration&amp;gt;
IAB VAST 2.0 §3.7.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other rules are less obvious than a missing required element:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VAST-2.0-mediafile-https: HTTP  URL on HTTPS inventory (mixed-content, ad won't play)&lt;/li&gt;
&lt;li&gt;VAST-2.0-duration-format:  is 00:30 instead of 00:00:30 (strict players reject this, others misfire tracking events at the wrong times)&lt;/li&gt;
&lt;li&gt;VAST-4.1-mezzanine-recommended: no  on a 4.1 tag (SSAI platforms reject these for CTV)&lt;/li&gt;
&lt;li&gt;VAST-4.1-vpaid-apiframework: VPAID apiFramework in a 4.1 tag (deprecated, Roku and Fire TV skip it)&lt;/li&gt;
&lt;li&gt;VAST-2.0-duplicate-impression: same impression URL appears twice (both sides double-count, neither report is technically wrong, they just never match)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core library is vastlint-core on crates.io, a pure Rust library with no external dependencies. The VS Code extension loads it as a WebAssembly module so validation runs locally with no network calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;string in -&amp;gt; parse XML -&amp;gt; detect VAST version -&amp;gt; run rule set -&amp;gt; issues out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typical validation time on a real-world CTV tag is under 100 microseconds. The WASM overhead adds a bit in the editor context but it's imperceptible while typing.&lt;/p&gt;

&lt;p&gt;The same core powers a CLI (cargo install vastlint), a REST API on RapidAPI, an MCP server for Claude/Cursor/Windsurf, and the online validator at vastlint.org.&lt;/p&gt;

&lt;h2&gt;
  
  
  Per-rule configuration
&lt;/h2&gt;

&lt;p&gt;Not every rule applies to every context. Mezzanine is noise for browser-only inventory but critical for Roku. You can tune per-rule in settings.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vastlint.rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"VAST-4.1-mezzanine-recommended"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"VAST-2.0-mediafile-https"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"VAST-4.1-vpaid-apiframework"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Valid levels: "error", "warning", "info", "off".&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I ran into this problem at work. The available tooling was either proprietary, behind a paywall, or only checked structure against the XSD. The spec is public. The failure modes are documented. There was no good reason an open-source implementation didn't exist.&lt;/p&gt;

&lt;p&gt;The other thing: these errors get caught way too late. A malformed tag makes it through QA, gets sent to the partner, fails on their platform, and shows up three weeks later in a discrepancy report. The campaign has already run, the impressions are gone. Catching it in the editor before the file leaves your machine is the right fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=aleksUIX.vastlint" rel="noopener noreferrer"&gt;Install from VS Code Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aleksUIX/vastlint" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vastlint.org/validate" rel="noopener noreferrer"&gt;Online validator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vscode</category>
      <category>adtech</category>
      <category>opensource</category>
      <category>rust</category>
    </item>
    <item>
      <title>The 10 VAST Errors That Silently Kill Your CTV Ad Revenue</title>
      <dc:creator>Aleksander Sekowski</dc:creator>
      <pubDate>Wed, 08 Apr 2026 01:35:58 +0000</pubDate>
      <link>https://forem.com/aleksuix/the-10-vast-errors-that-silently-kill-your-ctv-ad-revenue-25i8</link>
      <guid>https://forem.com/aleksuix/the-10-vast-errors-that-silently-kill-your-ctv-ad-revenue-25i8</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/@aleksander-sekowski/the-10-vast-errors-that-silently-kill-your-ctv-ad-revenue" rel="noopener noreferrer"&gt;Originally published on Medium.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Samsung TV Plus just crossed 100 million monthly active users. Netflix ended 2024 with 277.6 million subscribers worldwide, 70 million on its ad-supported tier. Amazon Prime Video had 230 million users. Roku reported 89.8 million active accounts in Q4 2024. The ad spend flowing through all of it: $33 billion in the US alone in 2024 runs on VAST XML.&lt;/p&gt;

&lt;p&gt;Every impression, every pixel, every billing event depends on a tag being parsed correctly by players, ad servers, and measurement vendors that were built by different teams to different tolerances. Penthera found that 40% of VOD ads fail. Google Ad Manager flags any gap larger than 25% between impressions served and impressions counted as a sign of systemic VAST errors. Most of these failures trace back to a handful of tag-level mistakes that are trivially detectable before the ad ever reaches a player.&lt;/p&gt;

&lt;p&gt;I built an open-source tool that catches all errors mentioned below: vastlint. 108 rules across VAST 2.0 through 4.3. Free, no account, runs in CI in about 100 microseconds per tag.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/aleksUIX" rel="noopener noreferrer"&gt;
        aleksUIX
      &lt;/a&gt; / &lt;a href="https://github.com/aleksUIX/vastlint" rel="noopener noreferrer"&gt;
        vastlint
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;vastlint&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://crates.io/crates/vastlint-cli" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2beb5b5855b57656861b67861574aecb4cee782d97520ddfa281e7698b6b629d/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f766173746c696e742d636c692e7376673f6c6162656c3d6372617465732e696f" alt="crates.io"&gt;&lt;/a&gt;
&lt;a href="https://crates.io/crates/vastlint-core" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a72af7d00fdcded39a6a5c8dff3c947cabcea697d93e6ca79d588d146ccdae79/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f766173746c696e742d636f72652e7376673f6c6162656c3d766173746c696e742d636f7265" alt="crates.io"&gt;&lt;/a&gt;
&lt;a href="https://docs.rs/vastlint-core" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2e66f1a456a606735a90cc9cc47c2b60e78d103706a464beed69a6b0912e8b93/68747470733a2f2f646f63732e72732f766173746c696e742d636f72652f62616467652e737667" alt="docs.rs"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/vastlint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f57064e4b17dcbd17fc10fce20ffadc141f9da635abec86d173144a8c552d152/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f766173746c696e742e7376673f6c6162656c3d6e706d" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://github.com/aleksUIX/vastlint/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/25a5325411ddfdd46094f1e6a698dac67891eaf213c5891a8a6c76f3466091fe/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f6c2f766173746c696e742d636c692e737667" alt="license"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A VAST XML validator. Checks ad tags against the IAB Tech Lab VAST specification so you don't have to read it. Over $30 billion in annual CTV and video ad spend flows through VAST XML, and malformed tags are one of the most common causes of lost impressions, broken tracking, and revenue discrepancies between platforms. There is no widely adopted open-source tool that validates VAST XML against the full IAB specification across all published versions.&lt;/p&gt;
&lt;p&gt;Validates VAST documents against:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://iabtechlab.com/standards/vast/" rel="nofollow noopener noreferrer"&gt;IAB Tech Lab VAST&lt;/a&gt; 2.0, 3.0, 4.0, 4.1, 4.2, and 4.3 -- structural rules derived from the published XSD schemas and spec prose&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/TR/xml/" rel="nofollow noopener noreferrer"&gt;W3C XML 1.0&lt;/a&gt; well-formedness (malformed documents are rejected before any spec rule runs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.rfc-editor.org/rfc/rfc3986" rel="nofollow noopener noreferrer"&gt;RFC 3986&lt;/a&gt; URI syntax (all URL fields)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.iana.org/assignments/media-types/" rel="nofollow noopener noreferrer"&gt;IANA Media Types&lt;/a&gt; (MediaFile and resource MIME types)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.iso.org/iso-4217-currency-codes.html" rel="nofollow noopener noreferrer"&gt;ISO 4217&lt;/a&gt; currency codes (Pricing elements)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ad-id.org/" rel="nofollow noopener noreferrer"&gt;Ad-ID&lt;/a&gt; registry format (UniversalAdId)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;108 rules across required fields, schema validation, structural correctness…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/aleksUIX/vastlint" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Here are the ten I see most often.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Missing  attributes&lt;br&gt;
delivery, type, width, height — all four are required. Leave one out and the player guesses. CTV devices don't guess well. A tag that plays fine in Chrome fails on Roku because the device won't infer the delivery method from context. The XML is valid. The spec is violated. The blank slot is yours.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HTTP media URLs on HTTPS inventory&lt;br&gt;
A  pointing at http:// gets blocked by mixed-content policies on any HTTPS page or app. The ad doesn't play, the impression doesn't fire, fill rate drops. The tag is valid XML. It's technically spec-compliant. It just won't work on most real inventory. This one is invisible to any validator that only checks structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bad  format&lt;br&gt;
The spec requires HH:MM:SS or HH:MM:SS.mmm. Tags show up with 00:30, 30s, plain 30, or empty. Strict players reject the creative outright. Loose players guess wrong and fire progress events — firstQuartile, midpoint, complete — at the wrong times. Your reporting looks fine but the measurement is off.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No  element&lt;br&gt;
No  URL means the ad plays but nobody gets paid. The DSP doesn't know it rendered, the SSP can't bill. Both sides pull discrepancy reports and argue. On wrapper chains it's worse. A missing impression at any level means that link in the transaction goes unrecorded. The outer wrapper fires, the inner wrapper doesn't, the numbers never reconcile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wrapper without &lt;br&gt;
A  with no redirect URL is a dead end. The slot goes unfilled, no error fires, the demand partner reports zero delivery. Usually happens when a template renders a wrapper variant but the URL variable is null or empty. At scale, that's thousands of lost impressions per minute with nothing in the logs pointing at the cause.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt; missing or malformed&lt;br&gt;
Required on every  since VAST 4.0. Needs an idRegistry attribute and a non-empty value. Without it, frequency capping and competitive separation break. The ad server can't tell two creatives apart, so it can't enforce exclusion rules between competing brands or cap a user who's already seen the ad five times. The ads still serve. The contracts you're supposed to be honoring don't.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VPAID apiFramework on VAST 4.1+ tags&lt;br&gt;
VPAID was deprecated in VAST 4.1. Google, Amazon, and most major SSPs block VPAID execution entirely. Tags declaring apiFramework="VPAID" pass XML validation. They may even pass some linting tools that only check structure. They get filtered before reaching a screen. Fill rate craters and the root cause is a single attribute value that no one thought to check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tracking event typos&lt;br&gt;
The spec defines a fixed set: creativeView, start, firstQuartile, midpoint, thirdQuartile, complete, and so on. Misspell one — Midpoint, mid_point, MidPoint — and no player fires it. The pixel silently never calls. VAST 4.0 also removed fullscreen and exitFullscreen. Tags copied from 3.0 templates still carry those events. They worked. They don't anymore.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Malformed XML&lt;br&gt;
Unescaped &amp;amp;, unclosed elements, bad UTF-8. Common when tags are assembled by string concatenation instead of an XML library. Many ad servers have lenient parsers that silently fix this. CTV devices don't. You debug a blank slot for an afternoon and the problem is &amp;amp; instead of &amp;amp; in a click URL buried three wrappers deep.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Version declaration doesn't match content&lt;br&gt;
The tag says  but contains  and , which are 4.x elements. The player applies 2.0 parsing rules and skips what it doesn't recognize. Happens constantly when templates are copied between projects without updating the version attribute. Everything looks fine in dev. In production the player is running a different code path than you think.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every one of these is detectable before the tag reaches a player. None of them require a live ad server, a real device, or a debugging session.&lt;/p&gt;

</description>
      <category>adtech</category>
      <category>rust</category>
      <category>node</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
