Skip to content

Reject non-string Info keys and values in info() - #1255

Open
Sonica-B wants to merge 1 commit into
prometheus:masterfrom
Sonica-B:fix/info-non-str-values
Open

Sonica-B wants to merge 1 commit into
prometheus:masterfrom
Sonica-B:fix/info-non-str-values

Conversation

@Sonica-B

Copy link
Copy Markdown

Anyone who passes a number (or any other non-string) to Info.info() loses their whole /metrics endpoint: the call succeeds, and every later scrape of that registry fails with AttributeError: 'int' object has no attribute 'replace', so all metrics, not only the Info one, disappear. #1046 reports this with a float temperature; #521, #583 and #1011 hit the same failure earlier. The docs already say "val must be a dict[str, str] — both keys and values must be strings", but info() only rejects None (#1012).

This change makes info() raise ValueError for any key or value that is not a str, at the call that caused it, so the registry stays scrapeable. It does not coerce values to strings, following the comment on #1046 that enforcing strings lets users correct the mistake.

Refs #1046

flowchart LR
    subgraph Before
        A1["Info.info({'build_number': 42})"] --> B1["stored in Info._value"]
        B1 --> C1["generate_latest() / openmetrics generate_latest()"]
        C1 --> D1["AttributeError: whole scrape fails"]
    end
    subgraph After
        A2["Info.info({'build_number': 42})"] --> B2["ValueError at the call site"]
        B2 --> C2["previous value kept; scrape returns all metrics"]
    end
Loading

Before and after

from prometheus_client import CollectorRegistry, Gauge, Info, generate_latest

registry = CollectorRegistry()
Gauge('up_ok', 'An unrelated metric', registry=registry).set(1)
build = Info('build', 'Build information', registry=registry)
try:
    build.info({'version': '1.2.3', 'build_number': 42})
except ValueError as e:
    print('info() raised:', e)
try:
    print(generate_latest(registry).decode())
except Exception as e:
    print('scrape failed:', type(e).__name__, e.args[0])

Before (e2f2bf9):

scrape failed: AttributeError 'int' object has no attribute 'replace'

After:

info() raised: Info keys and values must be strings, got 'build_number': 42
# HELP up_ok An unrelated metric
# TYPE up_ok gauge
up_ok 1.0
# HELP build_info Build information
# TYPE build_info gauge
build_info 1.0

A non-string key ({1: 'x'}) failed the same way before (TypeError: object of type 'int' has no len() at scrape time) and is now rejected by the same check.

Changes

  • prometheus_client/metrics.py: Info.info() checks that every key and value is a str before storing the dict. The existing None check and its message are unchanged.
  • tests/test_core.py: TestInfo.test_non_string_keys_and_values covers an int, a float, a non-string key and a list, for an Info with and without labels, and checks that the previous value survives and that both the text and the OpenMetrics output still render. It fails on master and passes with the change.

Testing

Windows 11, Python 3.11.9:

  • pytest tests -q: 440 passed, 14 skipped
  • flake8 prometheus_client/ tests/: clean
  • isort --check prometheus_client/ tests/: clean
  • mypy prometheus_client/ tests/: the same 9 missing-optional-dependency errors as on master, none new

Info.info() accepted any key or value except None. A non-string such as
{'build_number': 42} was stored, and every later scrape of the registry
then failed with AttributeError ("'int' object has no attribute
'replace'"), so one bad call hid all metrics on the endpoint.

Check the types where the value is set, as was done for None in prometheus#1012,
so the caller gets a ValueError and the registry stays scrapeable. The
docs already say both keys and values must be strings.

Refs prometheus#1046

Signed-off-by: Sonica-B <shreyaa.boyane@gmail.com>

This branch has not been deployed

No deployments
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.

1 participant