Docs
Rule reference
Every issue carries a stable id and, where it applies, the JSON path that tripped it. The id is the contract: it does not change when wording changes, so you can match on it in CI.
Issue codes are not the whole rule set
The 144 ids below are the diagnostic codes: the kinds of finding RTBlint can report. They are not the body of rules. Each code is parameterized by the object, field, and version that tripped it, and the knowledge behind them comes from three sources:
- 64 versioned rules across OpenRTB 2.0 through 3.0, each with its own code (for example
openrtb.2.2.regs.coppaoropenrtb.2.3.imp.native) describing a field that was added, deprecated, moved, removed, or corrected in a specific release. - Per-version object catalogs defining every object and field. The 2.6-202606 catalog alone covers 38 objects and 417 fields; across all 18 tracked versions that is 485 objects and 10,614 field definitions. Every presence, type, enum, and undefined-field check is driven by these.
- A semantic rule pack of cross-field checks the catalogs alone cannot express: SupplyChain node hygiene, GPP and US Privacy string coherence, CTV ad-pod duration sanity, native request encoding, and tmax/currency/bidfloor plausibility.
So a single code like openrtb.type.mismatch stands behind hundreds of concrete field checks. The table is the taxonomy; the catalog and rule pack are the coverage.
Diagnostic codes
Each code has its own page covering what it means, why it costs money, how to fix it, and a payload fragment that trips it. Click through any row.
openrtb.payload.invalid_jsonerrorThe payload is not parseable JSON. No field rules run until this is fixed.openrtb.payload.root_not_objecterrorThe JSON parses but the root is not an object. A bid request must be a single JSON object.openrtb.field.requirederrorA field the specification marks as required is missing at this path.openrtb.field.undefinederrorThe field is not defined in the canonical OpenRTB catalog for the selected version. Usually a typo or an invented key.openrtb.field.deprecatedwarningThe field still parses but is deprecated in the selected version. Migrate to its replacement.openrtb.field.movederrorThe field moved to a different path in this version, for example regs.ext.gdpr to regs.gdpr.openrtb.field.removederrorThe field was removed in the selected version and is no longer valid.openrtb.field.not_yet_availableerrorThe field belongs to a later version than the one selected, so it is not valid against this snapshot.openrtb.field.requires_skippable_videoerrorThe field only applies to skippable video and was used where skippability is not in effect.openrtb.fields.mutually_exclusiveerrorTwo fields that cannot coexist were both present. Keep one.openrtb.imp.media_type.requirederrorAn impression has no media-type object. Each imp needs a banner, video, audio, or native object.openrtb.type.mismatcherrorThe value has the wrong JSON type, for example a string where an integer is expected.openrtb.value.invaliderrorThe value is outside the documented set or range for this field, such as an out-of-range enum.openrtb.version.unsupportederrorThe targeted version has no usable catalog. Validation refuses rather than passing the payload silently.openrtb.request.tmax_non_positiveerrortmax is zero or negative, leaving no time for bids to be received.openrtb.request.tmax_implausiblewarningtmax is unusually high for an RTB auction; likely seconds instead of milliseconds.openrtb.request.cur_format_invalidwarningA cur entry is not a three-letter uppercase ISO-4217 currency code.openrtb.imp.bidfloor_negativeerrorbidfloor is negative; a CPM price cannot be negative. Also fires on Deal.bidfloor.openrtb.imp.bidfloorcur_format_invalidwarningbidfloorcur is not a three-letter uppercase ISO-4217 currency code. Also fires on Deal.bidfloorcur.openrtb.regs.gpp_sid_without_gppwarninggpp_sid is present but gpp is absent or empty.openrtb.regs.gpp_without_gpp_sidwarninggpp is present but gpp_sid is absent or empty.openrtb.regs.gpp_malformedwarningregs.gpp does not decode as a GPP v1 header (type 3, version 1, Fibonacci section range), or uses an illegal character, or has no '~' sections.openrtb.regs.gpp_section_mismatchwarningThe section ids encoded in the GPP header disagree with regs.gpp_sid, or the number of '~' payloads does not match the header.openrtb.regs.tcf_malformedwarninguser.consent, or a GPP section that should be TCF (sids 2 and 5), is not a TCF 2 core string (starts with C, long enough, TCF alphabet).openrtb.regs.us_privacy_malformedwarningus_privacy does not match the IAB US Privacy string shape: "1" followed by three Y/N/- characters.openrtb.schain.duplicate_nodewarningTwo adjacent SupplyChain nodes share the same asi and sid, as if a node were appended twice.openrtb.schain.node.hp_missingwarningA SupplyChain node has no hp field; the spec expects it to be propagated on every node.openrtb.schain.node.identifier_emptyerrorA SupplyChain node's asi or sid is an empty string.openrtb.schain.ver_unexpectedwarningSupplyChain ver is something other than 1.0, the only published version.openrtb.schain.incompletewarningcomplete is 0, declaring that at least one upstream node is missing from the path.openrtb.schain.length_implausiblewarningThe declared path has more than ten nodes, which is far longer than a real supply path.openrtb.schain.duplicate_locationwarningA supply chain is declared at both source.schain and source.ext.schain.openrtb.schain.node.hp_unexpectedwarningA SupplyChain node sets hp to something other than 1.openrtb.schain.node.asi_not_domainwarningA node's asi is not a bare domain: it carries a scheme, a path, a port, or whitespace.openrtb.schain.node.asi_not_lowercasewarningA node's asi contains uppercase characters; canonical domains are lowercase.openrtb.resolve.sellers_json_unavailablewarningThe local cache has no sellers.json for this node's asi, so the hop cannot be authorised.openrtb.resolve.sellers_json_unparseablewarningThe cached sellers.json for this hop exists but cannot be read as a sellers.json document.openrtb.resolve.sid_not_in_sellerserrorThis node's sid does not match any seller_id in the cached sellers.json for its asi.openrtb.resolve.ads_txt_unavailablewarningThe local cache has no ads.txt for site.domain, so the first payment hop cannot be checked against the publisher's authorization file.openrtb.resolve.ads_txt_unauthorizederrorThe publisher's ads.txt does not list the first payment node's asi and sid as DIRECT or RESELLER.openrtb.resolve.app_ads_txt_unavailablewarningThe local cache has no app-ads.txt for app.bundle, so the first payment hop cannot be checked against the app's authorization file.openrtb.resolve.app_ads_txt_unauthorizederrorThe app's app-ads.txt does not list the first payment node's asi and sid as DIRECT or RESELLER.openrtb.video.pod.rqddurs_emptywarningvideo.rqddurs is present as an empty array.openrtb.video.pod.mincpmpersec_without_pod_contextwarningvideo.mincpmpersec is present without poddur or maxseq, which normally accompany a dynamic ad pod.openrtb.native.request.double_encodederrornative.request parses to another JSON string rather than an object: it was JSON-encoded twice.openrtb.native.request.unparseablewarningnative.request does not parse as JSON at all.openrtb.native.request.legacy_wrapperwarningnative.request is wrapped in a top-level "native" key, the pre-Native-1.1 convention.openrtb.native.assets_missingerrorThe Native Markup Request or Response has no assets array, or it is empty, and the response has no assetsurl either.openrtb.native.asset.id_requirederrorA native asset has no integer id, so the response cannot be mapped back to the request.openrtb.native.asset.id_duplicateerrorTwo native request assets share the same id, so a response cannot map assets unambiguously.openrtb.native.asset.subtype_requirederrorA native asset has none of those subtypes, or more than one.openrtb.native.field_requirederrorA Native Ads field the spec marks required is absent: title.len, data.type, video mimes/protocols/duration, eventtracker event/methods, or response text/url/vasttag/value/link.url.openrtb.native.layout_removedwarningThe encoded native request still carries layout, which Native 1.1 replaced with plcmttype and context.openrtb.native.value.invaliderrordata.type, img.type, eventtrackers.event, or methods carries a value Native Ads does not list (and it is below the vendor range 500+).openrtb.native.asset.required_missingerrorThe native request marked an asset required, and the bid's adm does not return that id.openrtb.native.asset.id_unknownerrorThe native adm returns an asset id the request never asked for.openrtb.native.asset.type_mismatcherrorThe response filled a request title slot with an image, or the other way around.openrtb.response.seatbid_or_nbr.requirederrorA bid response has neither a seatbid nor a no-bid reason code (nbr).openrtb.bid.mtype_missingwarningA bid carries adm markup but no mtype, on a version that defines mtype. The buyer is leaving the markup type to be sniffed.openrtb.macro.unknownwarningnurl, burl, lurl, or adm contains ${NAME} where NAME is not a documented AUCTION_* macro.openrtb.bid.price_macro_missingwarningnurl or burl is present but neither contains ${AUCTION_PRICE}, so the notice cannot report the clearing price.openrtb.bid.loss_macro_missingwarninglurl is present without ${AUCTION_LOSS}, so the notice cannot report why the bid lost.openrtb.bid.adm.double_encodederroradm parses to another JSON string rather than an object: the native markup response was JSON-encoded twice.openrtb.bid.adm.native_not_jsonerrormtype 4 declares native markup, but adm is not a JSON Native Markup Response.openrtb.bid.adm.markup_type_mismatcherrorThe adm payload contradicts the declared mtype, for example a banner bid carrying a JSON payload.openrtb.bid.adm.vast_root_missingwarningA video or audio bid's adm is XML but has no VAST or DAAST document root.openrtb.bid.adm.not_markupwarningA video or audio bid's adm does not start with an XML tag, so it is unlikely to be a VAST document.openrtb.pair.request_unusableerrorCross-validation was asked for, but the paired bid request does not parse or is not an object.openrtb.response.request_id_mismatcherrorThe response id does not echo the id of the bid request it answers.openrtb.response.cur_not_allowederrorThe response bids in a currency the request did not list in cur.openrtb.seatbid.seat_not_allowederrorThe seat is absent from the request's wseat allowlist, or present in its bseat blocklist.openrtb.bid.impid_unknownerrorA bid's impid does not match the id of any Imp in the bid request.openrtb.bid.mtype_not_offerederrorThe bid's mtype names a media type the referenced Imp does not offer, for example a banner bid on a video-only imp.openrtb.bid.adm.media_type_mismatcherrorThe markup sniffed from adm does not match any media subtype the referenced Imp offers.openrtb.bid.dealid_unknownwarningThe bid's dealid is not among the referenced Imp's pmp deals. Out-of-band deals exist, so this is a warning.openrtb.envelope.missingerrorAn OpenRTB 3.0 payload has no openrtb wrapper. Sending a 2.x payload to a 3.0 validator lands here, with a note on where each object moved.openrtb.envelope.ver_mismatchwarningThe envelope's ver declares a different OpenRTB version than the one being validated against.openrtb.envelope.domainspec_unsupportedwarningThe envelope names a domain spec other than AdCOM, so the objects under item.spec and bid.media are left unchecked.adcom.placement.subtype_requirederroritem.spec.placement has none of the media subtype objects AdCOM requires.adcom.ad.subtype_requirederrorbid.media.ad has none of the media subtype objects AdCOM requires.adcom.asset.subtype_requirederrorA native Asset object has none of the subtype objects AdCOM requires.adcom.assetformat.subtype_requirederrorA native AssetFormat object has none of the format subtype objects AdCOM requires.openrtb.pair.unsupported_versionwarningRequest/response cross-validation was asked for on OpenRTB 3.0; the checks are 2.x-only, so the response was validated on its own.openrtb.dialect.bool_for_integererrorA flag field arrived as a boolean. The specification types it as an integer, but the IAB OpenRTB protobuf schema declares it bool, so this is a protobuf JSON payload sent to a spec JSON reader.openrtb.dialect.integer_for_boolerrorThe payload was validated as protobuf JSON, and a field the OpenRTB protobuf schema declares bool arrived as an integer. A protojson parser rejects the whole payload.openrtb.dialect.camel_case_namewarningA field arrived under the lowerCamelCase name protojson emits by default, such as privateAuction for private_auction. The field was resolved and validated, but a JSON reader will not find it.openrtb.eid.field_requirederrorAn Extended Identifier object has no source, no uids array, or a UID with no id.openrtb.sua.browsers_emptywarningdevice.sua is present but browsers is missing or empty, so it cannot replace device.ua.openrtb.skadn.field_requirederrorimp.ext.skadn or bid.ext.skadn is present but lacks a field the IAB SKAdNetwork OpenRTB extension requires.openrtb.profile.field_requirederrorAn exchange profile was declared, and a field that exchange documents as required is missing or empty.openrtb.profile.prebid.bidder_requirederrorThe Prebid Server profile was declared, and this Imp has no bidder targeting and no stored request that would supply it after merge.openrtb.profile.field_forbiddenerrorThe payload contains a field the declared exchange documents as invalid on that endpoint.openrtb.profile.value_invaliderrorA field the exchange documents has a closed value set, and this payload is outside it.artf.payload.invalid_jsonerrorThe RTBRequest or RTBResponse could not be parsed as JSON, so no envelope or mutation check can run.artf.payload.root_not_objecterrorThe payload parses but its root is not an object. An RTBRequest and an RTBResponse are each a single message.artf.field.requirederrorThe envelope is missing one of id, lifecycle, tmax, or bid_request, which the ARTF specification marks required.artf.field.undefinederrorThe envelope carries a member the ARTF proto does not define. Protobuf JSON rejects unknown fields by default.artf.field.type_mismatcherrorbid_request or bid_response is present but is not a JSON object, so there is nothing to validate inside it.artf.tmax.not_integererrortmax carries a non-integer value. It is the milliseconds the exchange allows for mutations to come back.artf.tmax.non_positiveerrortmax is zero or negative, so the call is already out of budget when it arrives.artf.tmax.implausiblewarningtmax exceeds 1000ms. The extension point runs inside an auction the exchange is already timing out, so a budget this large usually means seconds were sent as milliseconds.artf.lifecycle.unknownerrorThe lifecycle value is not one the ARTF enum defines, so the agent cannot tell which auction stage it is being called at.artf.lifecycle.unspecifiederrorThe stage is explicitly unset, so the agent does not know which payload is authoritative or which intents apply.artf.lifecycle.payload_mismatcherrorlifecycle is LIFECYCLE_DSP_BID_RESPONSE but the envelope has no bid_response, so response-stage intents have nothing to target.artf.lifecycle.payload_unexpectedwarninglifecycle is LIFECYCLE_PUBLISHER_BID_REQUEST, which runs before any DSP has answered, yet the envelope carries a bid_response.artf.originator.type_unknownerrorThe business entity type is outside the enum, so the agent cannot tell whose payload it is being asked to change.artf.originator.id_missingwarningThe originator names a type but no identity, so the agent cannot tell which business entity owns the payload.artf.intents.missingwarningThe agent is not told which intents it may return, and the orchestrator has no declared basis for rejecting the ones it gets.artf.intents.not_arrayerrorapplicable_intents is a repeated field, so its JSON form is an array even when it holds one value.artf.intents.emptywarningThe list is present but empty, so every mutation the agent returns is out of scope by definition.artf.intent.unknownerrorOne of the declared intents is not an ARTF Intent value, so the agent cannot tell what is actually being offered.artf.request_unusableerrorThe envelope passed alongside the mutation set is not a JSON object, so no mutation can be checked against the auction it targets.artf.response.id_missingerrorThe response carries no id, so the orchestrator cannot tie the mutations back to the extension point call it made.artf.response.id_mismatcherrorThe response id is not the extension point request id. The envelope id is not the bid request id, and confusing the two is the common failure.artf.response.metadata_missingwarningWithout api_version and model_version, an orchestrator cannot record which agent build produced these mutations.artf.mutations.emptywarningThe agent returned an empty mutation set, so the orchestrator paid for the call and has nothing to evaluate.artf.mutation.not_objecterrorAn entry in the mutations array is not a Mutation object, so it carries no intent, operation, or path to check.artf.mutation.intent_unknownerrorThe declared intent is outside the enum, so the orchestrator cannot tell why the change is being proposed.artf.mutation.intent_unspecifiederrorThe mutation declares no purpose, so it cannot be evaluated independently, which is what ARTF requires of every change.artf.mutation.intent_not_applicableerrorThe mutation declares an intent the orchestrator did not offer on this call, so it is rejected on arrival.artf.mutation.op_unknownerrorThe operation is outside the enum, so the orchestrator cannot tell whether to add, replace, or remove at the target path.artf.mutation.op_unspecifiederrorThe operation is unset, so the change has a target and a value but no verb.artf.mutation.op_not_applicablewarningThe mutation removes at a path while declaring an intent that adjusts a price or a floor, where replace is the operation that applies.artf.mutation.path_missingerrorpath is required: it is the semantic reference naming which auction entity the mutation applies to.artf.mutation.path_not_absoluteerrorARTF semantic paths are rooted at the payload, so they begin with /.artf.mutation.path_unrecognizedwarningThe path is rooted and well formed but is not one of the semantic references ARTF v1.0 documents, so only a prior agreement can resolve it.artf.mutation.path_intent_mismatchwarningThe intent and the path disagree: segment activation pointed at a bid, or bid shading pointed at an impression.artf.mutation.imp_unknownerrorThe imp id in the path is not among the impressions in the bid request the envelope carried.artf.mutation.deal_unknownerrorThe deal id in the path is not among the deals the impression's pmp object carries, so there is no floor or margin to adjust.artf.mutation.bid_unknownerrorThe seat and bid id in the path do not resolve to a bid in the carried bid response.artf.mutation.target_payload_missingerrorThe path addresses a bid and the RTBRequest has no bid_response to mutate.artf.mutation.payload_missingerrorThe mutation names an intent and a target but carries none of the value oneof members, so there is nothing to apply.artf.mutation.payload_ambiguouserrorvalue is a protobuf oneof, so exactly one payload member may be present.artf.mutation.payload_intent_mismatcherrorThe mutation sets a payload member the intent does not carry, such as adjust_bid on a deal activation.artf.mutation.ids_emptyerrorThe mutation proposes no ids, so it changes nothing while still consuming an evaluation slot.artf.mutation.bidfloor_negativeerrorThe floor adjustment carries a negative price, which OpenRTB has no meaning for.artf.mutation.margin_negativeerrorThe margin adjustment carries a negative value, whether it is expressed as CPM or as a percentage.artf.mutation.margin_implausiblewarningA PERCENT margin above 100 would take the whole bid and more.artf.mutation.price_missingerrorBID_SHADE proposes a new bid price, and adjust_bid.price is absent.artf.mutation.price_negativeerrorThe shaded price is below zero, which no auction can settle.artf.mutation.metrics_emptyerrorADD_METRICS proposes no metrics, so the mutation adds nothing to the impression.artf.mutation.metric_type_missingerrorOpenRTB requires Metric.type. Without it, whoever receives the mutated request cannot interpret the value.artf.mutation.no_openrtb_targetwarningMargin is not part of the OpenRTB Deal object, so the orchestrator has to apply it out of band and no validator can check the result.artf.mutation.legacy_spec_encodingwarningThe mutation is written the way the ARTF v1.0 document's examples are, with camelCase intents and a value wrapper, rather than the enum names and oneof members its own .proto defines.Severities
An error means the payload is invalid against the selected version. A warning means it still parses but uses something deprecated you should migrate away from. The tester counts each separately so you can gate on errors and triage warnings.
See what RTBlint checks for the categories behind these ids, or OpenRTB versions for how the selected snapshot changes which ids fire.