Skip to content

VAST 4.4: xs:choice minOccurs=0 maxOccurs=unbounded on vastInLine_type / vastWrapper_type drops all child cardinality #58

Description

@aleksUIX

In vast_4.4.xsd on master, both vastInLine_type and vastWrapper_type wrap their children in:

<xs:choice minOccurs="0" maxOccurs="unbounded">

That compositor discards every cardinality constraint on the children it contains. The child elements still declare minOccurs="1", but inside a repeating optional xs:choice those values only govern a single selection, not the content model as a whole. The net effect is that all children become optional, all become unboundedly repeatable, and ordering is no longer constrained.

I do not think this was intended, but it may be a deliberate consequence of the CTV Ad Portfolio restructure, so I wanted to check rather than assume.

Reproduction

All three validate against vast_4.4.xsd as published on master:

xmllint --noout --schema vast_4.4.xsd empty-wrapper.xml

1. Empty <Wrapper/>: no AdSystem, no VASTAdTagURI, no Impression.

<VAST version="4.4" xmlns="http://www.iab.com/VAST">
  <Ad id="a"><Wrapper/></Ad>
</VAST>

2. Empty <InLine/>: no AdSystem, no AdTitle, no Impression, no Creatives.

<VAST version="4.4" xmlns="http://www.iab.com/VAST">
  <Ad id="a"><InLine/></Ad>
</VAST>

3. <AdSystem> repeated three times.

<VAST version="4.4" xmlns="http://www.iab.com/VAST">
  <Ad id="a">
    <InLine>
      <AdSystem>A</AdSystem>
      <AdSystem>B</AdSystem>
      <AdSystem>C</AdSystem>
    </InLine>
  </Ad>
</VAST>

Element order is also unconstrained, so <Impression> before <AdSystem> validates.

Comparison with 4.2

In vast_4.2.xsd, Wrapper_type extends AdDefinitionBase_type and both use xs:sequence:

Type Compositor AdSystem Impression VASTAdTagURI
4.2 AdDefinitionBase_type xs:sequence 1..1 1..unbounded n/a
4.2 Wrapper_type (extends above) xs:sequence inherited 1..1 inherited 1..unbounded 1..1
4.4 vastWrapper_type xs:choice 0..unbounded effectively 0..unbounded effectively 0..unbounded effectively 0..unbounded

The same empty <Wrapper/> correctly fails against 4.2:

Element '{http://www.iab.com/VAST}Wrapper': Missing child element(s). Expected is ( {http://www.iab.com/VAST}AdSystem ).

So 4.4 is currently more permissive here than 2.0 through 4.2, and an empty ad container is schema-valid for the first time.

Why it matters

Impression has been required on wrappers since 2.0. Anything using the XSD as a gate (ad server ingest checks, QA tooling, partner certification) will now pass 4.4 wrapper responses that cannot possibly deliver or measure an ad. It also interacts with issue #40 and the wider question of whether the XSD is meant to be usable as a validator, which came up there.

Possible direction

If the goal was "these children may appear in any order", xs:all expresses that while preserving per-element cardinality. XSD 1.0 restricts xs:all to maxOccurs="1" per particle, so repeating elements like Impression would need handling, but it keeps the required ones required. If the goal really was a fully open content model, then the prose and the schema have diverged and it would be worth saying so explicitly in the annotation.

Happy to open a PR against the 4.4 draft with a xs:all based content model for both types, or with a minimal change that just restores required AdSystem / Impression / VASTAdTagURI on vastWrapper_type, whichever direction the group prefers.

Checked against vast_4.4.xsd at master on 2026-08-09, validated with xmllint (libxml2).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions