Skip to content

Add HuggingFace auth and 429 retry handling to HTTP downloads - #815

Draft
warmbowski wants to merge 5 commits into
mainfrom
paull/hf-http-ratelimit-retry
Draft

warmbowski wants to merge 5 commits into
mainfrom
paull/hf-http-ratelimit-retry

Conversation

@warmbowski

@warmbowski warmbowski commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Add HuggingFace auth and 429 retry handling to HTTP downloads

Why

Checkpoints now load from public HuggingFace bucket URLs. A distributed checkpoint load issues many concurrent ranged GETs, which trips HF's per-window rate limit: nothing sent an HF_TOKEN (anonymous requests get the lowest rate tier) and 429 responses weren't retried.

Changes

  • Add _http_auth_headers(), which attaches Authorization: Bearer $HF_TOKEN for hosts in a host → env var registry (huggingface.co, hf.co). Returns no header when the env var is unset, so anonymous access is unchanged.
  • Send those headers from _http_file_size(), _http_get_bytes_range(), and _http_file_exists().
  • Pass those headers through the cached_path() calls that read trainer state and checkpoint metadata (resource_path() in io.py, Checkpoint.load() and the ephemeral-check read in train/checkpoint.py), which previously requested anonymously.
  • Add HTTP_RETRY_STATUS_CODES = (429, 502, 503, 504) and HTTP_MAX_RETRIES as the single retry policy for HTTP.
  • Add _build_http_session(), which builds a pooled session and optionally attaches a urllib3 retry policy honoring Retry-After. _get_http_session() now delegates to it.
  • Add _RetryableHttpClient, a cached-path scheme client for http(s):// that retries HTTP_RETRY_STATUS_CODES; registered in add_cached_path_clients(). Subclasses cached-path's HttpClient because get_scheme_client() only forwards custom headers to clients derived from it, and treats exhausted retries as recoverable so a cached copy can be used.
  • Change _http_retry_condition() to read HTTP_RETRY_STATUS_CODES instead of a hardcoded (429, 502), and apply it to all three _http_* helpers.
  • Add response.raise_for_status() to _http_file_size() so error statuses surface as HTTP errors rather than a missing content-length error, and raise FileNotFoundError on 404 to match the GCS and S3 equivalents.
  • Rename the io.py cached-path section header to cover both clients.
  • Add tests for the auth headers and for the retryable client's registration, header forwarding, and retry policy.

Notes

  • HF_TOKEN (read scope) raises the rate limit tier; unset leaves behavior as before.
  • Retries honor Retry-After but not HF's RateLimit: t=<reset> header.
  • The adapter-level policy is only applied to sessions whose callers don't already retry via @retriable, so retries don't stack.

🤖 Generated with Claude Code

@warmbowski warmbowski changed the title Paull/hf http ratelimit retry hugging face auth and retry for http bucket endpoints Aug 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ecb4e74ef4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

save_folder=opts.save_folder,
save_overwrite=True,
load_path="https://storage.googleapis.com/ai2-llm/checkpoints/OLMo25/step596047/",
load_path="https://huggingface.co/buckets/allenai/ai2-llm/resolve/checkpoints/OLMo25/step596047/",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pass HF auth through cached checkpoint downloads

For these new https://huggingface.co/... checkpoint paths, the first checkpoint reads still go through cached_path() before the new HTTP range helper is used: trainer state is loaded with cached_path(path) in Checkpoint.load(), and DCP .metadata is loaded via resource_path(...)/cached_path() in RemoteFileSystemReader.read_metadata(). Since _http_auth_headers() is only wired into _http_file_exists() and range reads, a cold-cache load from a private or rate-limited HF bucket still sends no HF_TOKEN for those metadata/trainer-state requests and can fail with 401/429 before tensor range reads begin; please pass the same headers into cached_path/resource_path or use an HF-aware scheme before switching these official load paths.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will look into this and see about making it work for cached/resource path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

okay, looks like cached_path has a headers arg that only applies to http requests. This fits perfectly

headers :
        Custom headers to add to HTTP requests.
        Example: ``{"Authorization": "Bearer YOUR_TOKEN"}`` for private resources.
        Only used for HTTP/HTTPS resources.

@baileykuehl baileykuehl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!

@warmbowski
warmbowski force-pushed the paull/hf-http-ratelimit-retry branch from 1b602e7 to 60c16ae Compare August 11, 2026 16:09

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60c16ae07e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/olmo_core/io.py
else:
return cached_path(f"{folder}/{fname}", quiet=True)
url = f"{folder}/{fname}"
return cached_path(url, quiet=True, headers=_http_auth_headers(url))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Retry cached HTTP checkpoint downloads on 429

After this patch, the fresh evidence is that this new cached_path(...headers=...) path still bypasses the new _http_retry_condition; cached_path does the cold-cache HEAD/download for resource_path() before RemoteFileSystemReader reaches the range-read helper, and the trainer-state cached_path call has the same shape. For rate-limited Hugging Face checkpoint URLs, a transient 429 on .metadata or train/rank*.pt can still abort checkpoint loading without the retry behavior this commit adds for direct HTTP range/head reads.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

looking into this now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

code added to support 429 retry in the cached_path

@warmbowski warmbowski changed the title hugging face auth and retry for http bucket endpoints Add HuggingFace auth and 429 retry handling to HTTP downloads Aug 11, 2026
@warmbowski
warmbowski requested a review from baileykuehl August 11, 2026 18:32

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92a9f4c3c9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/olmo_core/io.py
and exc.response.status_code == 502
),
)
@retriable(retry_condition=_http_retry_condition)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Honor Retry-After for range-read retries

When a checkpoint is loaded without pre_download, RemoteFileSystemReader._get_bytes() calls get_bytes_range() for each tensor shard, so a Hugging Face 429 on this _http_get_bytes_range() path is retried by the generic retriable wrapper. That wrapper only sleeps _wait_before_retry() (capped at 3s) and never reads exc.response.headers['Retry-After'], unlike the new cached-path session; if HF returns a longer reset window, all retries are spent before the window opens and the load still fails. Please either use the retry-aware session here or teach retriable to honor the HTTP header for this condition.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Trying to avoid scope creep on this. I can take care of this if you really want me to, but this should suffice for now.

Comment thread src/olmo_core/io.py
Comment on lines +698 to +699
if response.status_code == 404:
raise FileNotFoundError(url)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this is a bit of an exiting bug fix that brings it in line with the other http* methods. I think we want to raise this before checking the content-length

@warmbowski

Copy link
Copy Markdown
Contributor Author

I am unsure that this PR should go in with the http auth code added. It turns out that it isn't solving the issue of allowing external users to get better rate limits on bucket access when using an hf token. I am going to put this in draft until we figure out if what we want is even possible.

@warmbowski
warmbowski marked this pull request as draft August 12, 2026 21:17
@warmbowski

Copy link
Copy Markdown
Contributor Author

It looks like connecting to our allenai bucket with an hf token is possible with the correct token permissions. This will get higher rate limits for end users and just about eliminate 429 errors in the run, even on the free tier. Anonymous access still face a lot of 429 errors.

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