DEV Community

Aleksander Sekowski
Aleksander Sekowski

Posted on

OpenRTB 2.6 Spelled a Device Field 'didshal' for Six Months. Which Snapshot Are You Validating Against?

Most people treat "OpenRTB 2.6" as a version number. It is closer to a release train. Since 2022 the IAB has published dated snapshots of 2.6, each one adding fields, and occasionally fixing the previous one.

Here is what that looks like as field-level drift across the snapshots, diffed from the generated schemas:

2.6-202210 -> 2.6-202211:  +10 -0
   added:   dooh, dt, gpp, gpp_sid, inventorypartnerdomain, multiplier,
            qty, sourcetype, venuetype, venuetypetax
2.6-202303 -> 2.6-202309:  +13 -3
   added:   acat, count, didsha1, dpidsha1, durfloors, guar, maxdur,
            mindur, minint, plcmt, refresh, refsettings, reftype
   removed: didshal, dpidshal, kwarry
2.6-202309 -> 2.6-202402:  +1 -0
   added:   poddedupe
2.6-202409 -> 2.6-202501:  +3 -0
   added:   inserter, matcher, mm
2.6-202501 -> 2.6-202505:  +3 -0
   added:   cids, genres, gtax
2.6-202505 -> 2.6-202606:  +2 -0
   added:   firstbroadcast, realtime
Enter fullscreen mode Exit fullscreen mode

That November 2022 row is a real feature release: dooh brought digital out-of-home into 2.6, and gpp / gpp_sid brought the Global Privacy Platform. Fine, expected, that is what version numbers are for.

Now look at the removals in the second row. didshal, dpidshal, kwarry. Those are not deprecated features. They are typos in the specification that were live for two snapshots and then corrected.

The typos

From the March 2023 snapshot of the OpenRTB 2.6 spec, in the Device object table:

<td><code>didshal</code></td>
<td>string; DEPRECATED</td>
<td>Hardware device ID (e.g., IMEI); hashed via SHA1.</td>
Enter fullscreen mode Exit fullscreen mode

The description says SHA1. The field name ends in a lowercase L. It should be didsha1, and the same slip hit dpidshal. Two fields, one wrong character each, in the canonical table that implementers read to build their bidders.

The other one is subtler because the correct spelling was in the same document:

<!-- in the Site object -->
<td><code>kwarray</code></td>
<td>Array of keywords about the site.</td>

<!-- in the Content object, same document -->
<td><code>kwarry</code></td>
<td>Array of keywords about the site.</td>
Enter fullscreen mode Exit fullscreen mode

kwarray under Site and App, kwarry under Content, with the Content entry also carrying the copy-pasted "about the site" description. Both spellings live in the March 2023 snapshot at once.

All three were fixed in the September 2023 snapshot. The current spec has didsha1 and kwarray and no trace of the others:

$ curl -s https://raw.githubusercontent.com/InteractiveAdvertisingBureau/openrtb2.x/main/2.6.md \
  | grep -c 'didshal\|kwarry'
0
Enter fullscreen mode Exit fullscreen mode

Why this is not just trivia

Consider what a validator built against the March 2023 snapshot does when a real bidder sends the field everyone actually implemented:

{ "device": { "didsha1": "5f4dcc3b5aa765d61d8327deb882cf99" } }
Enter fullscreen mode Exit fullscreen mode

It rejects it as an unknown field, because in that snapshot the field is called didshal. And it accepts didshal, which nothing in production sends.

That is not a thought experiment. Same payload, two catalogs:

$ rtblint validate --version 2.6-202303 dev.json
FAILED (OpenRTB 2.6-202303 bid request): 1 error(s), 0 warning(s).
- [error] device.didsha1: Device.didsha1 is not defined in the canonical
  OpenRTB 2.6-202303 catalog. (openrtb.field.undefined) ยท spec 3.2.18

$ rtblint validate --version 2.6-202606 dev.json
OK with warnings (OpenRTB 2.6-202606 bid request): 1 warning(s).
- [warning] device.didsha1: device.didsha1 is deprecated in OpenRTB 2.6-202606.
  (openrtb.field.deprecated)
Enter fullscreen mode Exit fullscreen mode

A hard error on the left, a correct deprecation notice on the right, for a field name that has been the real one all along.

The failure is inverted. Your validator is strictest about the thing it has wrong. Anyone shipping code from that snapshot got a validator that punishes correct behaviour, and because unknown-field handling is usually a warning rather than a hard failure, the signal is easy to tune out.

This generalises past the typos. Every one of those +N rows is a field that a bidder might send you and that an older catalog will call unknown. poddedupe arrived in February 2024. mm and inserter in January 2025. firstbroadcast and realtime in June 2026. If you validate a 2026 bid request against a 2023 catalog, you get a pile of unknown-field noise that is entirely your own tooling's fault, and the natural reaction is to disable unknown-field checking altogether, which is exactly the check you wanted.

Pin the snapshot deliberately

The fix is not "always use the newest." It is to make the version an explicit, visible choice rather than whatever your library happened to vendor.

rtblint is an OpenRTB linter I maintain, and it carries a separate extracted catalog per snapshot rather than one merged superset:

$ rtblint validate --version 2.6-202303 request.json   # what your partner implemented
$ rtblint validate --version 2.6-202606 request.json   # what the spec says today
Enter fullscreen mode Exit fullscreen mode

Running both is the useful move. The diff between the two reports is your compatibility surface with that partner, expressed as a list rather than a guess.

It tracks 2.0, 2.1, 2.2, 2.3, 2.3.1, 2.4, 2.5, nine dated 2.6 snapshots, and 3.0. One snapshot, 2.6-202204, says so out loud rather than silently passing payloads:

$ rtblint validate --version 2.6-202204 dev.json
FAILED: OpenRTB 2.6-202204 has no canonical BidRequest catalog in this build;
bid request validation is not supported for this version.
(openrtb.version.unsupported)
Enter fullscreen mode Exit fullscreen mode

That is a deliberate choice. A validator that falls back to a neighbouring version when it does not have the right catalog is worse than one that refuses, because the first kind produces confident wrong answers and the second kind produces a bug report.

If you want to check your own stack

Two questions worth answering today, both cheap:

Which snapshot is your validator using? If the answer is "2.6" with no date, that is the finding. Something in your dependency tree picked a date for you.

Does it accept didsha1? A one-line test against a request containing that field tells you whether you are on a pre-September-2023 catalog:

$ echo '{"id":"1","imp":[{"id":"1","banner":{"w":300,"h":250}}],
  "site":{"id":"s"},"device":{"didsha1":"abc"}}' \
  | rtblint validate --stdin
Enter fullscreen mode Exit fullscreen mode

The generated JSON Schemas are published per snapshot if you would rather diff them yourself, and the version reference lists what changed at each step.

The broader habit

Dated snapshots inside a version number are an unusual pattern, and tooling ecosystems handle them badly because most versioning assumes a single ordered sequence of releases. OpenRTB 2.6 has nine of them and counting, they are not semver, and nothing in a package.json will tell you which one your validator believes in.

Treat the snapshot date as part of the version. Write it down in the integration doc next to the endpoint URL. When a partner says "we support 2.6," the useful follow-up is "as of when."

Top comments (0)