Skip to content

Boot-time capabilities validation error does not name the failing field #1896

Open

Description

@bokelley

What happens

When create_adcp_server_from_platform runs the boot validator (validate_capabilities_response_shape), a schema violation raises:

AdcpError: INVALID_REQUEST / terminal: get_adcp_capabilities response failed boot-time spec validation: response does not conform to protocol/get-adcp-capabilities-response.json. Fix the platform's capabilities declaration ...

The failing fields are in error.details["issues"], as a pointer, message, keyword and schema_path for each issue. A pod log or an uncaught traceback prints only the message, though, so the operator can't tell what failed.

We hit this on adcp 10.0.0b13. A reporting doorbell (media_buy.reporting_delivery.ledger_notification) beside webhook_signing.supported: false broke allOf[13] of the 3.3.0-beta.5 schema, with these issues:

  • /webhook_signing/supported: value does not match the required constant
  • /webhook_signing/profile: 'profile' is a required property
  • /webhook_signing/algorithms: 'algorithms' is a required property

Every replica crash-looped for hours, and the log never showed those three lines. We had to reproduce the failure locally to find them.

The same message is raised at request time, from PlatformHandler.get_adcp_capabilities (decisioning/handler.py, where it calls _validate_response_dict for request-scoped capabilities). There it reaches a buyer as INVALID_REQUEST, which is just as opaque.

Where

src/adcp/decisioning/validate_capabilities.py, _validate_response_dict. The schema branch is:

raise _violation(
    "response does not conform to protocol/get-adcp-capabilities-response.json",
    details={"issues": [...]},
)

Proposal

Put the issues in the message itself. For example: up to the first 5 issues as <pointer>: <message>, joined with ; , then and N more when there are more. Keep the full list in details. Also name the schema version the response was validated against, since the rules differ between releases (this one applies from 3.2 on).

... response does not conform to protocol/get-adcp-capabilities-response.json (AdCP 3.3.0-beta.5): /webhook_signing/supported: value does not match the required constant; /webhook_signing/profile: 'profile' is a required property; /webhook_signing/algorithms: 'algorithms' is a required property

Related: misleading chained exception

_invoke_capabilities calls asyncio.run(handler.get_adcp_capabilities()) inside the except RuntimeError: block that follows its asyncio.get_running_loop() probe. Any error the handler raises therefore prints as During handling of the above exception (RuntimeError: no running event loop), another exception occurred. That reads like an event-loop bug and sent us looking at the wrong thing.

Fix: probe first, then call asyncio.run outside the except block:

try:
    asyncio.get_running_loop()
except RuntimeError:
    running = False
else:
    running = True
if running:
    cause = RuntimeError("asyncio.run() cannot be called from a running event loop")
    raise _running_loop_error(cause) from cause
return asyncio.run(handler.get_adcp_capabilities())

Workaround

An adopter can catch AdcpError around serve() and log error.details. The Scope3 embedded sales agent does this now: https://github.com/scope3data/embedded-sales-agent/pull/1230.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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