Skip to content

Conversation

@LukoJy3D
Copy link

@LukoJy3D LukoJy3D commented Nov 7, 2025

In prometheus/prometheus#16155, it was suggested to clarify it in exposition formats.

While writing it, I feel that some aspects overlap with those mentioned in https://prometheus.io/docs/instrumenting/content_negotiation/. Therefore, it may be sufficient to mention it in the migration guide, but I will give this a try.

@LukoJy3D LukoJy3D force-pushed the docs/exposition/clarify_required_content_type_for_scrapes branch from 2c77a01 to 4b70e1b Compare November 7, 2025 21:06
Copy link
Member

@bwplotka bwplotka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

This is great addition, but I propose to word things a bit differently, see the comment. WDYT? Is that helpful? (:

Comment on lines +174 to +185
At minimum, set the `Content-Type` media type to one of:

- `application/openmetrics-text`
- `text/plain`
- `application/vnd.google.protobuf`

Adding parameters such as `version=` (e.g. `text/plain;version=1.0.0`) is **optional**. Prometheus will correctly negotiate the protocol based solely on the media type. For the canonical list of protocols, parameters, and the negotiation rules, see [Scrape protocol content negotiation](./content_negotiation.md).

### Common pitfall

The value of the `Content-Type` header must be a **valid MIME type** — plain tokens like `OpenMetricsText1.0.0` are **not valid** and the scrape will fail. Use the full media type instead, `application/openmetrics-text;version=1.0.0'`. See [Protocol Headers](./content_negotiation.md#protocol-headers) for details.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this is bit misleading. Content type depends on what you actually expose, but it reads here like it's a random string to put. (:

What if we make it clearer what the content type is for each section above?

Prometheus text format already mentions content type.

  • In Proto section let's mention application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited
  • In OpenMetrics section application/openmetrics-text;version=<version>

Version is NOT always optional. It matters. Especially with OpenMetrics, because there will be breaking changes between application/openmetrics-text;version=1.0.0 and (upcoming) application/openmetrics-text;version=2.0.0

Then we could say:

Suggested change
At minimum, set the `Content-Type` media type to one of:
- `application/openmetrics-text`
- `text/plain`
- `application/vnd.google.protobuf`
Adding parameters such as `version=` (e.g. `text/plain;version=1.0.0`) is **optional**. Prometheus will correctly negotiate the protocol based solely on the media type. For the canonical list of protocols, parameters, and the negotiation rules, see [Scrape protocol content negotiation](./content_negotiation.md).
### Common pitfall
The value of the `Content-Type` header must be a **valid MIME type** — plain tokens like `OpenMetricsText1.0.0` are **not valid** and the scrape will fail. Use the full media type instead, `application/openmetrics-text;version=1.0.0'`. See [Protocol Headers](./content_negotiation.md#protocol-headers) for details.
See each of the exposition format sections for the accurate HTTP content types.
### ScrapeProtocols vs Content-Type
Prometheus scrape config offers to configure negotiation based on the content-type using the [`scrape_protocols`](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config) config. For the Prometheus user convenience the scrape protocols are referenced by a unique name that maps to the concrete content-type. See the current (v3.7.3) mapping [here](https://github.com/prometheus/prometheus/blob/v3.7.3/config/config.go#L556).
However, the targets should expose metrics in the exposition format with the absolute, response content-type (e.g. `application/openmetrics-text;version=1.0.0`) and only one.

Copy link
Member

@bwplotka bwplotka Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I just noticed https://prometheus.io/docs/instrumenting/content_negotiation lol, so maybe a bit simpler:

Suggested change
At minimum, set the `Content-Type` media type to one of:
- `application/openmetrics-text`
- `text/plain`
- `application/vnd.google.protobuf`
Adding parameters such as `version=` (e.g. `text/plain;version=1.0.0`) is **optional**. Prometheus will correctly negotiate the protocol based solely on the media type. For the canonical list of protocols, parameters, and the negotiation rules, see [Scrape protocol content negotiation](./content_negotiation.md).
### Common pitfall
The value of the `Content-Type` header must be a **valid MIME type** — plain tokens like `OpenMetricsText1.0.0` are **not valid** and the scrape will fail. Use the full media type instead, `application/openmetrics-text;version=1.0.0'`. See [Protocol Headers](./content_negotiation.md#protocol-headers) for details.
See each of the exposition format sections for the accurate HTTP content types.
### ScrapeProtocols vs Content-Type
Prometheus scrape config offers scrape protocol negotiation based on the content-type using the [`scrape_protocols`](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config) config. For the Prometheus user convenience the scrape protocols are referenced by a unique name that maps to the concrete content-type. See [Protocol Headers](./content_negotiation.md#protocol-headers) for details.
However, the targets should expose metrics in the exposition format with the absolute, response content-type (e.g. `application/openmetrics-text;version=1.0.0`) and only one.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants