Skip to content

apps API: Accept with protobuf first and JSON as a fallback gets 406 instead of JSON #5297

Open

Description

A client that prefers protobuf and accepts JSON as a fallback gets 406 Not Acceptable from the apps API instead of a JSON answer. GET on an Application with Accept: application/vnd.kubernetes.protobuf, application/json;q=0.9 returns 406. With application/cbor, application/json;q=0.9 the same request returns JSON. TestAppsAPIContentNegotiation in pkg/cmd/server/apiserver_surface_test.go (#4869) pins both answers as they are today.

The cause is that the apps API advertises a media type it cannot encode. pkg/apiserver serves through serializer.NewCodecFactory(Scheme), wrapped in kindPreservingSerializer, and that factory lists protobuf among its supported media types. Negotiation in k8s.io/apiserver picks the best match from that list, so protobuf wins over the JSON fallback. Encoding then fails because the Application types do not implement the protobuf marshalling interface. The protobuf serializer reports that as errNotMarshalable, whose status is 406 (k8s.io/apimachinery pkg/runtime/serializer/protobuf/protobuf.go), and the response never goes back to JSON. CBOR is not in the factory's list, so negotiation skips it and the fallback works.

Upstream custom resources behave the same way. apiextensions-apiserver also lists protobuf for them, because some objects it returns, like Status, do support it. So this is not specific to cozystack, but the result still breaks the Accept header's promise: JSON was acceptable and the server had it.

Two ways to handle it:

  1. Drop protobuf from the media types the apps group negotiates, so a fallback in Accept is honoured. Objects like Status that the apps API returns would then be served as JSON too, which needs checking against clients that send protobuf only.
  2. Keep the upstream behaviour and treat the pinned 406 as the contract. The test already describes the mechanism, so only this issue would close.

I'd go with the first, but it is a change to what the API advertises, so it needs a maintainer decision.

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

    triage/needs-triageIndicates an issue needs triage by a maintainer

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions