What the messages mean

Back to the validator. Message ids are stable, so tools can key on them. Each message names its basis, and its severity follows from it. An error breaks a requirement: a MUST in the specification (basis MUST), a MUST of an RFC it builds on (RFC), or a normative statement written without a key word (Rule). A warning departs from a recommendation: a SHOULD (SHOULD), the Guides, which call each item "a recommendation, in the sense of SHOULD" (Guides), or our answer to a question the draft leaves open (Reading). Info reports something worth knowing that breaks nothing, such as a field this version doesn't define (agents ignore those, so later versions can add fields). Only errors make documents invalid. What our own Personal Agent refuses is a separate choice, shown where it differs: it also refuses a few warnings that guard against hostile documents, and tolerates a few errors the draft tells readers to tolerate.

The JSON report

outputVersion
1. Changes that break readers of the report get a new number.
outcome
valid (no errors), invalid (an error), or indeterminate (a document couldn't be fetched, or not within the limits the Guides recommend, so it couldn't be checked).
refused
Whether our Personal Agent refuses these documents: an error it doesn't tolerate, a warning it refuses, or a document it couldn't check.
checkedAgainst
The protocol version whose rules were applied, chosen from poppy.json's protocol_version.
documents
Each document checked: kind, url, finalUrl after redirects, status, contentType, maxAgeSeconds, and the parsed value.
messages
id, basis (MUST, RFC, Rule, SHOULD, Guides or Reading), severity, refuses (whether our agent refuses the documents over it), document, pointer (a JSON Pointer), line and column (1-based) when known, text, and ref (the section of the specification or RFC).
skipped
Checks that needed something the input didn't give, such as the domain a pasted poppy.json was served from.

Messages

Unsupported protocol version

version-unsupported · Error · Basis: MUST · Spec 3.1

Before 1.0, every major.minor version can break compatibility. An agent must explicitly support the declared version.

Fix: Use a supported protocol version or upgrade the agent.

Not an HTTPS URL

http-not-https · Error · Basis: MUST · Spec 3

Discovery documents, metadata and key sets are fetched only over HTTPS.

Fix: Serve the document over HTTPS and link to it with an https:// URL.

Not a public host

http-non-public-host · Warning · Basis: Guides, but our agent refuses it · Guides: Fetching metadata safely

The Guides ask Personal Agents and Companies to refuse loopback, private and link-local addresses unless configured on purpose (a recommendation, not a requirement of the draft). By name alone, this validator, like our client, never fetches IP literals, single-label hosts, or special-use and private-use names such as localhost, .local, .internal and .home.arpa, so it can't check a document there. A name can still resolve to a private address: on Cloudflare Workers the platform refuses those connections, and the command-line validator checks each address a name resolves to (http-non-public-address). Used as a library elsewhere, it checks names only, so the caller must supply a fetcher that checks addresses.

Fix: Publish the document on a public DNS name.

Resolves to a private address

http-non-public-address · Warning · Basis: Guides, but our agent refuses it · Guides: Fetching metadata safely

The Guides ask Personal Agents and Companies to refuse loopback, private and link-local addresses, judged by the address actually connected to (a recommendation, not a requirement of the draft). The host name is public, but it resolves to such an address (loopback, RFC 1918, link-local, carrier-grade NAT, unique local, unspecified, multicast or another range that isn't globally reachable), so nothing was checked there. The command-line validator resolves each name itself, refuses these, and connects only to the address it checked.

Fix: Point the name at a public address.

Redirect to a non-HTTPS URL

http-redirect-not-https · Error · Basis: MUST · Spec 3

Every redirect from the well-known URL must be to an HTTPS URL. Agents stop at the first one that isn't.

Fix: Make each Location header an https:// URL.

Too many redirects

http-too-many-redirects · Warning · Basis: Guides, but our agent refuses it · Guides: Fetching metadata safely

The draft says agents MUST follow redirects but sets no limit; the Guides recommend a few at most. This validator, like our client, follows 3.

Fix: Redirect straight to where the document lives.

Client metadata is served by a redirect

http-redirect-not-allowed · Warning · Basis: Guides, but our agent refuses it · Guides: Verifying personal agents

client_id MUST equal the URL the document was fetched from (4.1), and the Guides tell Companies to fetch it without following redirects, so a redirect there fails verification at Companies that do, and this validator, like our client with any document, doesn't follow it. Only the Guides say not to follow redirects here, and the Guides are recommendations, so this is a warning.

Fix: Serve the client metadata document directly at its client_id URL.

Not served with HTTP 200

http-status · Error · Basis: MUST · Spec 3

The document must be served successfully for anyone to use it.

Fix: Serve the document with status 200.

Couldn't fetch the document

http-failed · Warning · Basis: Guides, but our agent refuses it · Guides: Fetching metadata safely

The request failed before a response arrived: DNS, TLS, the connection, or the timeout (10 seconds, the top of the Guides' "few seconds", so a serverless Company's cold start fits). Nothing was checked, and our client can't use a document it couldn't fetch.

Fix: Check that the URL is reachable from the public internet and answers within a few seconds.

Document too large

http-too-large · Warning · Basis: Guides, but our agent refuses it · Guides: Fetching metadata safely

The Guides recommend capping what is read from another party's URL, such as at 100 KB; the draft sets no size. Our client, and this validator, stop at 100 KB.

Fix: Keep the document under 100 KB.

Not served as JSON

http-content-type · Warning · Basis: Reading · RFC 8259 §11

The response's Content-Type isn't application/json. Some agents and proxies won't treat it as JSON.

Fix: Serve it with Content-Type: application/json.

No caching headers

http-no-cache-headers · Info · Basis: SHOULD · Spec 3

Agents cache discovery documents according to HTTP caching headers. Without them each agent picks its own lifetime, typically the minimum (a minute).

Fix: Send Cache-Control with a max-age, such as max-age=3600.

Cache lifetime outside common bounds

http-cache-bounded · Info · Basis: Guides · Guides: Fetching metadata safely

Agents bound cache lifetimes, such as to between a minute and a day, so a removed key or endpoint stops being trusted. Values outside that are clamped.

Fix: Use a max-age between 60 and 86400 seconds.

Not UTF-8

not-utf8 · Error · Basis: RFC · RFC 8259 §8.1

JSON exchanged between systems MUST be encoded as UTF-8 (RFC 8259 §8.1); the Guides say the same.

Fix: Save and serve the document as UTF-8.

Starts with a byte order mark

json-bom · Error · Basis: RFC, but our agent tolerates it · RFC 8259 §8.1

JSON sent over a network MUST NOT begin with a byte order mark (RFC 8259 §8.1), so this is an error. The same section lets parsers ignore one, and our client does; other parsers reject it.

Fix: Remove the BOM at the start of the file.

Not valid JSON

json-syntax · Error · Basis: RFC · RFC 8259

The document isn't well-formed JSON, so nothing else can be checked.

Fix: Fix the syntax at the line and column given.

JSON location metadata exceeds the validator's resource allowance

json-resource-limit · Warning · Basis: Guides, but our agent refuses it · Guides: Fetching metadata safely

Our client limits cumulative escaped JSON-pointer strings to one million UTF-16 code units, before constructing them. A long member name repeated in every child's location can otherwise use far more memory than the document's byte size. This is an implementation policy for safely processing untrusted documents, not a JSON syntax error or a protocol requirement. Nothing was checked beyond this limit.

Fix: Shorten long nested member names or reduce the number of values beneath them.

Duplicate member name

json-duplicate-member · Warning · Basis: SHOULD, but our agent refuses it · Guides: Transport and JSON

An object has two members with the same name. Parsers disagree about which one wins. RFC 8259 §4 says names SHOULD be unique and the Guides recommend rejecting such objects; the draft has no MUST here, so this is a warning. Our client still refuses them: a document two parsers read differently can mean two things.

Fix: Remove one of the two members.

Required member missing

missing-member · Error · Basis: MUST · Spec 3.1

A member the specification requires isn't there.

Fix: Add the member described in the message.

Wrong type

wrong-type · Error · Basis: Rule · Spec 3.1

A member has the wrong JSON type, such as a string where an object is required.

Fix: Use the type given in the message.

Not an absolute URL

not-a-url · Error · Basis: Rule · Spec 3.1

The value must be an absolute URL with a host name (or an IP address), such as https://api.example.com/.

Fix: Use a full URL, starting with https://.

URL isn't HTTPS

not-https-url · Error · Basis: MUST · Spec 3.1

The draft requires HTTPS for auth.issuer, conversation endpoints, client_id, jwks_uri and redirect_uris, and OAuth requires it for the authorization server's endpoints.

Fix: Use an https:// URL.

URL isn't HTTPS (where the draft doesn't say)

not-https-url-unstated · Warning · Basis: Reading, but our agent refuses it · Spec 3.1

The draft doesn't require HTTPS for apis[].url, auth.mediated.endpoint (which receives passwords), web.browser_session_endpoint, extension endpoints or logo_uri (spec-issues N9). Our reading is that it does, since each of them receives tokens or credentials or is shown to the User, so this is a warning, and our client refuses a poppy.json that doesn't use HTTPS there.

Fix: Use an https:// URL.

URL has a fragment

url-has-fragment · Error · Basis: RFC · RFC 6749 §3.1

OAuth endpoints, issuers and redirect URIs can't contain a #fragment (RFC 6749 §3.1, §3.1.2, §3.2; RFC 8414 §2).

Fix: Remove the part after #.

URL has a fragment (where no rule forbids one)

url-has-fragment-unstated · Warning · Basis: Reading, but our agent refuses it · RFC 6749 §3.1

No rule forbids a #fragment in this URL, but a fragment is never sent to a server, so a URL that has one is a mistake or a trick. Our reading is that these URLs follow the OAuth rule too; this is a warning, and our client refuses the document.

Fix: Remove the part after #.

Member not defined in this version

unknown-member · Info · Basis: MUST · Spec 3.3

This version of the specification doesn't define the member, so agents ignore it. That is allowed: it lets later versions add fields. It may also be a typo.

Fix: Check the spelling. If it's deliberate, nothing to do.

protocol_version isn't major.minor

version-format · Error · Basis: Rule · Spec 3.1

protocol_version is a string of two numbers, such as "0.1".

Fix: Set protocol_version to "0.1".

Unsupported major version

version-unsupported-major · Error · Basis: MUST · Spec 3.1

A Personal Agent must not use a document whose major version it doesn't support. This validator knows the versions listed on the validator page.

Fix: Publish a document for a supported major version, or check a newer validator.

Historical newer-minor diagnostic

version-newer-minor · Info · Basis: Rule · Spec 3.1

Retained for older saved reports. Current validation uses explicit supported versions and refuses unknown 0.x drafts; this diagnostic is no longer emitted.

Fix: Nothing to do.

Not a domain name

domain-invalid · Error · Basis: Rule · Spec 3.1

The value must be a DNS host name, such as example.com, with no scheme, port or path.

Fix: Use the bare host name.

organization.domain doesn't match the requested domain

organization-domain-mismatch · Error · Basis: MUST · Spec 3.1

organization.domain must match the host of the well-known URL the agent requested, ignoring a leading www. The host it was redirected to doesn't count. Otherwise one domain could speak for another.

Fix: Set organization.domain to the domain whose /.well-known/poppy.json serves this document.

No display name

organization-name-missing · Error · Basis: Rule, but our agent tolerates it · Spec 3.1

organization is required and is the Company's "Display name and domain" (3.1): a normative statement without a key word, so this is an error. Our client tolerates it and shows the domain to the User instead (spec-issues S18).

Fix: Add organization.name, such as "Example Company".

auth is required

auth-required · Error · Basis: MUST · Spec 3.1

auth is required when agent, apis, or web.browser_session_endpoint is present, because all of them need Sessions.

Fix: Add auth with the Company's issuer, or remove the members that need Sessions.

No agent, apis or web

nothing-offered · Error · Basis: MUST · Spec 3.1

A poppy.json must offer at least one of agent, apis, or web.

Fix: Add the Company Agent, an API, or the website.

Website only

website-only · Info · Basis: Rule · Spec 3.1

Without auth, agents can't start Sessions, so they browse the site as ordinary signed-out visitors.

Fix: Add auth to offer Sessions, APIs or conversations.

No sign-in types

signed-out-only · Info · Basis: Rule · Spec 4.4

auth lists none of direct, device or mediated, so Sessions can only be signed out.

Fix: Add a sign-in type if agents should act on Users' accounts.

Issuer has a query

issuer-query · Error · Basis: RFC · RFC 8414 §2

An OAuth issuer identifier is an HTTPS URL with no query or fragment.

Fix: Remove the ?query from the issuer.

Invalid scope

scope-syntax · Error · Basis: RFC · RFC 6749 §3.3

Scopes follow OAuth scope syntax: printable ASCII with no spaces, double quotes or backslashes.

Fix: Rename the scope.

Reserved scope name

scope-reserved · Error · Basis: Rule · Spec 4.4

Names starting with poppy: are reserved for the protocol, which defines only poppy:read and poppy:write.

Fix: Rename the scope so it doesn't start with poppy:.

Custom scope has no description

scope-undescribed · Warning · Basis: Reading · Spec 4.4

A Company describes each scope it defines in auth.custom_scopes, so agents can explain to the User what they're granting.

Fix: Add the scope to auth.custom_scopes with a short description.

Described scope isn't offered

scope-unoffered · Info · Basis: Reading · Spec 4.4

auth.custom_scopes describes a scope that no sign-in type lists, so agents can never request it.

Fix: Add it to a sign-in type's scopes, or remove the description.

Sign-in type grants no scopes

scopes-empty · Warning · Basis: Reading · Spec 4.4

A sign-in type with an empty scopes list can't grant anything, so agents can't usefully use it.

Fix: List the scopes the type can grant.

Scope listed twice

scope-duplicate · Warning · Basis: Reading · Spec 4.4

The same scope appears twice in one list.

Fix: Remove the duplicate.

Mediated Sign-In lists no fields

mediated-fields-empty · Warning · Basis: Reading, but our agent refuses it · Spec 4.7

auth.mediated.fields lists the credentials the agent sends. The draft doesn't say it can't be empty, but without any, agents have nothing to send and can't sign in. Our reading, so a warning; our client refuses it.

Fix: List each credential with name, label and secret.

Credential field named twice

mediated-field-duplicate · Error · Basis: Rule · Spec 4.7

Each field's name is the key in credentials, so names must be unique.

Fix: Give each field a different name.

Field doesn't say whether it's secret

mediated-secret-missing · Warning · Basis: Reading · Spec 4.7

secret marks a value the agent must protect: never shown back, logged, or sent elsewhere. Without it, agents treat the value as not secret.

Fix: Add secret: true or secret: false.

Credential looks secret but isn't marked

mediated-looks-secret · Warning · Basis: Reading · Spec 4.7

The field's name or label looks like a password, PIN or code, but secret is false, so agents may show or log it.

Fix: Set secret: true.

Invalid resource

resource-invalid · Error · Basis: RFC · RFC 8707 §2

resource is a resource indicator: an absolute URI with no fragment.

Fix: Use the URL of the service, without a #fragment.

No poppy conversation protocol

no-poppy-protocol · Warning · Basis: Reading · Spec 7.1

agent.protocols has no entry of type poppy, the only conversation protocol the draft defines, so most agents can't talk to the Company Agent.

Fix: Add { "type": "poppy", "endpoint": "https://…" }.

Conversation protocol agents may not know

protocol-type-unknown · Info · Basis: Rule · Spec 7.1

Agents skip conversation protocol types they don't support.

Fix: Nothing to do, as long as a poppy entry is listed too.

API type not defined in this version

api-type-unknown · Error · Basis: MUST, but our agent tolerates it · Spec 6

Draft 0.1 says each API's type MUST be openapi or mcp, so in a document that declares a version this validator knows, another type is an error. The draft also says agents SHOULD skip types they don't recognise, and ours does: it skips the API and still uses the Company.

Fix: Use openapi or mcp, or leave the API out until a version of the protocol defines its type.

Unknown API type skipped

api-type-newer · Info · Basis: MUST · Spec 6

This supported profile skips an unrecognized API type. It does not infer support for an unknown protocol version. The diagnostic ID is retained for saved reports.

Fix: Nothing to do, unless agents should use this API.

API has no description

api-description-missing · Error · Basis: Rule, but our agent tolerates it · Spec 6

"Each has a type …, a url, and a short description" (3.1): a normative statement without a key word, so this is an error. Our client still uses the API.

Fix: Add a description, such as "Orders, returns, and exchanges".

MCP resource differs from its url

mcp-resource-mismatch · Warning · Basis: Reading · Spec 4.3

An MCP server accepts only tokens issued for its url, and agents request Bearer tokens with resource set to that url. A different resource here is ambiguous.

Fix: Leave out resource for MCP entries, or set it to the url.

Invalid extension name

extension-name · Error · Basis: MUST · Spec 3.3

Extensions defined with the protocol have plain names. Anyone else must start the name with a domain they control, such as example.com/gift-wrap.

Fix: Prefix the name with your domain and a slash.

Plain extension name the protocol doesn't define

extension-plain-unknown · Warning · Basis: Reading · Spec 3.3

Plain names are for extensions defined with the protocol; anyone else MUST use a name that starts with their domain (3.3). The Extensions page can define new plain-named extensions at any time, independently of the protocol version, so this validator can't tell a newly defined one from a misnamed one: our reading is a warning, not an error. Agents ignore extensions they don't support.

Fix: If it's your own extension, name it with your domain, such as example.com/gift-wrap.

Extension version this validator doesn't know

extension-version-unknown · Info · Basis: MUST · Spec 3.3

Agents that don't support this version of the extension ignore it.

Fix: Nothing to do.

Extension version is a number

extension-version-number · Warning · Basis: Reading · Spec 3.3

"Each entry has a version, the extension's major version" (3.3), but the draft doesn't give its JSON type (spec-issues N22); every example is a string, such as "1". Our reading is a string, so a number is a warning. Agents that compare it as a string, ours included, don't recognise the version and ignore the extension.

Fix: Write the version as a string, such as "1".

Metadata issuer doesn't match auth.issuer

metadata-issuer-mismatch · Error · Basis: MUST · Spec 3.2

The metadata's issuer must exactly equal auth.issuer, character for character. Otherwise any domain could claim another Company's issuer and receive its tokens.

Fix: Make the two strings identical, including any trailing slash.

poppy_domains doesn't include the domain

metadata-domain-missing · Error · Basis: MUST · Spec 3.2

poppy_domains must list every domain whose poppy.json names the issuer. Agents refuse a domain that isn't listed.

Fix: Add organization.domain to poppy_domains.

private_key_jwt not advertised

metadata-auth-method · Warning · Basis: Reading · Spec 4.1

Personal Agents authenticate at the token endpoint with private_key_jwt. The metadata lists other methods only.

Fix: Add private_key_jwt to token_endpoint_auth_methods_supported.

No supported algorithm for client assertions

metadata-signing-alg · Warning · Basis: Guides · RFC 8414 §2

Agents sign client assertions with ES256 or RS256. token_endpoint_auth_signing_alg_values_supported lists neither.

Fix: Add ES256, and RS256 if you can.

Grant type not advertised

metadata-grant-type · Warning · Basis: Reading · Spec 4.2

grant_types_supported leaves out a grant this Company needs for the sign-in types its poppy.json lists.

Fix: Add the grant type named in the message.

ES256 not advertised for DPoP

metadata-dpop-alg · Warning · Basis: Guides · RFC 9449 §5.1

Agents sign DPoP proofs with ES256 when they can, and dpop_signing_alg_values_supported doesn't list it.

Fix: Add ES256.

S256 not advertised for PKCE

metadata-pkce · Warning · Basis: Guides · Spec 4.5

Direct Sign-In uses PKCE with S256, and code_challenge_methods_supported doesn't list it.

Fix: Add S256.

Authorization responses may not carry iss

metadata-iss-parameter · Info · Basis: Rule · RFC 9207 §3

authorization_response_iss_parameter_supported isn't true. Agents that check iss on the redirect (RFC 9207), as ours does, can then tell Companies apart only by state.

Fix: Return iss in authorization responses and set the flag to true.

client_id isn't the URL it was fetched from

client-id-mismatch · Error · Basis: MUST · Spec 4.1

A Personal Agent's client_id must equal the URL its metadata document was fetched from.

Fix: Set client_id to the exact URL of this document.

URL on a different domain from client_id

client-other-domain · Error · Basis: MUST · Spec 4.1

jwks_uri and every redirect URI must be HTTPS URLs on the same domain as client_id.

Fix: Host them on client_id's domain.

Token endpoint auth method isn't private_key_jwt

client-auth-method · Error · Basis: Rule · Spec 4.1

Personal Agents authenticate with private_key_jwt (4.1), and the draft's example declares it. The draft has no MUST for the member, but without it OAuth's default (client_secret_basic, RFC 7591 §2) applies, which doesn't fit.

Fix: Set "token_endpoint_auth_method": "private_key_jwt".

No redirect URIs

client-no-redirects · Info · Basis: Rule · Spec 4.1

Without redirect_uris the agent can't use Direct Sign-In; Device and Mediated Sign-In still work.

Fix: Add the agent's Direct Sign-In callback URL.

No keys

jwks-empty · Error · Basis: Rule · Spec 4.1

The key set has no keys, so nothing the agent signs can be verified.

Fix: Publish at least one public signing key.

Private key material published

jwks-private-key · Error · Basis: Rule · Spec 4.1

The key set contains only public keys. This key has private members (d, p, q, dp, dq, qi or k), so the key is compromised.

Fix: Remove the key, generate a new one, and publish only its public part.

Unsupported key

jwks-key-type · Warning · Basis: Guides · Guides: Signing and verifying JWTs

The Guides say to support ES256 and RS256, so Companies may accept only EC P-256 and RSA keys. The draft doesn't restrict key types, so this is a warning.

Fix: Use an EC P-256 key, or an RSA key of at least 2048 bits.

RSA key too small

jwks-rsa-small · Error · Basis: RFC · RFC 7518 §3.3

RS256 MUST use a key of 2048 bits or larger (RFC 7518 §3.3); the Guides say the same.

Fix: Generate a 2048-bit or larger key, or use EC P-256.

Key algorithm isn't ES256 or RS256

jwks-alg · Warning · Basis: Guides · Guides: Signing and verifying JWTs

Companies support ES256 and RS256. A key marked with another alg may be ignored.

Fix: Use ES256 or RS256.

Key has no kid

jwks-no-kid · Warning · Basis: Guides · Guides: Rotating keys

Every key needs a kid so keys can be rotated and Companies can pick the right one.

Fix: Add a unique kid to each key.

Two keys share a kid

jwks-kid-duplicate · Warning · Basis: SHOULD · Guides: Rotating keys

Different keys in a key set SHOULD have different kids (RFC 7517 §4.5), and the Guides give every key one for rotation. Verifiers may pick the wrong key. A SHOULD, so this is a warning.

Fix: Give each key a unique kid.

Key isn't for signing

jwks-use · Warning · Basis: Reading · RFC 7517 §4.2

The key's use isn't "sig", so verifiers may refuse to check signatures with it.

Fix: Set use to "sig" or leave it out.