You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
hf auth login now defaults to a browser-based OAuth Device Code flow instead of asking you to copy-paste a token. The command prints a URL and a short code, you authorize in the browser, and the CLI retrieves and saves the token for you. The same applies to login() in Python. In an interactive terminal you still get a gh-style arrow-key menu to pick between browser login and pasting a token, and --token works exactly as before.
OAuth tokens expire after 30 days, but they come with a refresh token: get_token() transparently refreshes them when less than a day of validity remains, so long-running setups keep working without re-authenticating. hf auth list now shows the expiry date for OAuth tokens.
> hf auth login
? How would you like to log in? Log in with your browser
Open this URL in your browser:
https://hf.co/oauth/device
And enter the code: 52AT-FLYZ
Waiting for authorization.
When the command is run by an AI agent, it never prompts. Instead it streams structured events so the agent can surface the URL and code to its user, then blocks until a terminal auth_success / auth_error event:
⚡ Faster, more reliable hf upload for large folders
hf upload and the underlying upload_folder have been revamped to be faster and far more robust on large folders. When hf_xet is installed (the default), uploads now run through a streamed, multi-commit pipeline built on the XetSession API: the folder is scanned and fed into a background Xet upload while previous batches are committed in parallel, and files are hashed in a single read pass while they are chunked (the old flow read every large file twice). Nothing changes in how you call it:
hf upload <repo-id><path/to/folder>
This is a drop-in replacement for experimental hf upload-large-folder used until today, which will be deprecated in a future release.
🚨🚨 Breaking change: With the upload_folder and hf upload revamp, uploading a folder might result in multiple commits. It is also not possible to open a PR against a specific revision while using upload_folder. If you pass create_pr=True, it will necessarily create a PR against main. It will open the PR no matter if some changes have been committed (previously an empty commit was resulting in no PR opened at all).
What you get on large folders:
More reliable. Uploads are resumable and stateless. If an upload is interrupted, just re-run the same command: already-committed files are detected and skipped, and already-uploaded chunks are deduplicated by the Xet backend (≈0 bytes re-transferred). There are no local state files to go stale, so resume even works from a different machine.
Faster. Files are hashed while being chunked (single read pass) and batches commit in the background while the next batch is already uploading, so there is no separate hashing phase blocking the upload.
Multi-commit by default. Large folders are automatically split into adaptive commits that scale between 64 and 1024 files based on commit duration. Folders that fit in a single batch still produce exactly one commit, as before; follow-up commits get a (part N) suffix.
Live progress bar tracking the preparing, uploading, and committing stages (with a plain-log fallback when output is not a TTY):
upload_large_folder / hf upload-large-folder are intentionally left untouched in this release; their deprecation will follow once hf upload has fully absorbed the use case.
[Upload] Streamed multi-commit upload_folder powered by Xet by @Wauplin in #4331
💻 Jobs: wait, SSH access, and cleaner error messages
This release adds three major capabilities to Hugging Face Jobs.
Wait for completion.HfApi.wait_for_job() and hf jobs wait block until one or more Jobs reach a terminal stage, which makes it easy to chain commands in CI scripts. wait_for_job accepts a single id or a list, returns the final JobInfo even on failure (check job.status.stage), and only raises TimeoutError on timeout. The CLI exits 0 only if all waited-on Jobs ended COMPLETED.
# Wait on a single job, then run the next step only if it succeeded
hf jobswait<job_id>&& next-step
# Wait on a batch, with a timeout
hf jobswait<id1><id2> --timeout 10m
⚠️Breaking change: non-detached hf jobs run / hf jobs uv run now exit with the Job's outcome (exit code 1 if the Job errored) instead of always exiting 0. We consider this a bugfix — scripts relying on the old behavior were being silently misled — but it is called out here in case you depend on the previous exit code.
SSH access. With --ssh at launch and an SSH key registered on huggingface.co/settings/keys, you can connect straight into a running Job's container with hf jobs ssh <job_id>. Thanks to wait_for_job, hf jobs ssh now waits for the Job to reach RUNNING before connecting (with a status spinner) instead of failing immediately while it is still scheduling.
$ hf jobs run --ssh --detach python:3.12 sleep infinity✓ Job started id: 6a33ba2aef9220ea67d98a03 url: https://huggingface.co/jobs/Wauplin/6a33ba2aef9220ea67d98a03Hint: Use `hf jobs ssh Wauplin/6a33ba2aef9220ea67d98a03` to open an SSH session into the job.
$ hf jobs ssh Wauplin/6a33ba2aef9220ea67d98a03Job is running.Running `ssh 6a33ba2aef9220ea67d98a03@​ssh.hf.jobs`root@j-wauplin-6a33ba2aef9220ea67d98a03-do4bduvn-5f153-458k4:/#
Readable errors. A new JobNotFoundError and the switch from response.raise_for_status to hf_raise_for_status turn raw httpx tracebacks into clean, actionable messages. Per-command try/except blocks were removed in favor of the global CLI error handling.
$ hf jobs inspect 000Error: 404 Client Error. (Request ID: Root=1-6a316470-...)Job Not Found for url: https://huggingface.co/api/jobs/Wauplin/000.Please make sure you specified the correct job ID and namespace.Set HF_DEBUG=1 as environment variable for full traceback.
[Jobs] Add hf jobs wait and HfApi.wait_for_job by @Wauplin in #4345
[Jobs] Add SSH support to run a Job and connect to it by @Wauplin in #4352
[CLI] Make hf jobs ssh wait for job to be running by @Wauplin in #4379
🖥️ Custom-container deploy for Inference Endpoints
hf endpoints deploy can now deploy custom Docker containers end-to-end, no more hand-writing JSON and POSTing the raw endpoints API. New flags wire up the image and its runtime: --custom-image, --health-route, --port, --command, and --container-args. Environment variables and secrets can be injected with --env/--env-file and --secrets/--secrets-file. On the SDK side, create_inference_endpoint gains container_command and container_args parameters.
The type parameter now defaults to authenticated instead of the deprecated protected (passing protected emits a FutureWarning). The custom-container flags raise a clean error if used without --custom-image.
[Inference Endpoints] Custom-container deploy CLI + deprecate protected endpoint type by @gary149 in #4329
⏳ Wait for a Space with wait_for_space and hf spaces wait
Mirroring the new wait_for_job primitive, HfApi.wait_for_space() and hf spaces wait block until a Space leaves an intermediate stage (BUILDING, APP_STARTING, …) and settles on a final state. The CLI exits 0 if the Space is RUNNING, non-zero otherwise. hf spaces ssh and hf spaces dev-mode were refactored to use wait_for_space internally instead of the old CLI-only helper.
# Wait after a restart
hf spaces restart username/my-space && hf spaces wait username/my-space
# With a timeout
hf spaces wait username/my-space --timeout 5m
[Spaces] Add wait_for_space API and hf spaces wait CLI by @Wauplin in #4380
💔 Breaking Changes
🚨🚨 With the upload_folder and hf upload revamp, uploading a folder might result in multiple commits.
It is also not possible to open a PR against a specific revision while using upload_folder. If you pass create_pr=True, it will necessarily create a PR against main. It will open the PR no matter if some changes have been committed (previously an empty commit was resulting in no PR opened at all).
[Upload] Streamed multi-commit upload_folder powered by Xet in #4331 by @Wauplin
RepoUrl now rejects canonical single-segment repo IDs like "gpt2" or "datasets/squad" (use "user/gpt2" or "datasets/user/squad" instead). repo_type_and_id_from_hf_id is softly deprecated. parse_hf_uri gains an endpoint argument to parse URLs from self-hosted Hub instances.
[URIs] Use parse_hf_uri in RepoUrl + soft-deprecate repo_type_and_id_from_hf_id by @Wauplin in #4324
Non-detached hf jobs run / hf jobs uv run now exit with the Job's outcome (exit 1 on Job error) instead of always exiting 0
[Jobs] Add hf jobs wait and HfApi.wait_for_job by @Wauplin in #4345 — see the Jobs highlight above.
🖥️ CLI
[CLI] Suggest creating repo/bucket on NotFound errors by @Wauplin in #4372 — when a repo or bucket can't be found, the CLI now hints at the matching create command instead of just reporting the 404.
🔧 Other QoL Improvements
[HTTP] Retry on HTTP 408 Request Timeout by default by @Wauplin in #4360 — 408 Request Timeout is now part of the default retry status set, alongside the existing 5xx codes.
OIDC: Include error_description in HTTP error messages by @coyotte508 in #4341 — failed OIDC exchanges now surface the server's error_description, making misconfigured Trusted Publishers far easier to debug.
[Download] Retry on RemoteProtocolError in http_get by @Wauplin in #4351 — transient connection drops mid-download are now retried instead of failing the download.
Ignore Windows metadata files in cache scan by @Chinmay1220 in #4357 — desktop.ini and similar Windows metadata files no longer trip up scan-cache.
🏗️ Internal
[Tests] Add inference pytest marker to filter inference tests by @Wauplin in #4338
#14220: Fixed a logic bug in pytest.RaisesGroup which would might cause it to display incorrect "It matches FooError() which was paired with BarError" messages.
#14591: Fixed a regression in pytest 9.1.0 which caused overriding a parametrized fixture with an indirect @pytest.mark.parametrize to fail with "duplicate parametrization of '<fixture name>'".
#14606: Fixed list-item typing errors from mypy in @pytest.mark.parametrize <pytest.mark.parametrize ref>argvalues parameter.
#14608: Fixed a regression in pytest 9.1.0 where conftest.py files located in <invocation dir>/test* were no longer loaded as initial conftests when invoked without arguments.
This could cause certain hooks (like pytest_addoption) in these files to not fire.
Next steps: Take a moment to review the security alert above. Review
the linked package source code to understand the potential risk. Ensure the
package is not malicious before proceeding. If you're unsure how to proceed,
reach out to your security team or ask the Socket team for help at
support@socket.dev.
Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.
Mark the package as acceptable risk. To ignore this alert only
in this pull request, reply with the comment
@SocketSecurity ignore pypi/llama-cpp-python@0.3.31. You can
also ignore all packages with @SocketSecurity ignore-all.
To ignore an alert for all future pull requests, use Socket's Dashboard to
change the triage state of this alert.
Warn
Obfuscated code: pypi llama-cpp-python is 90.0% likely obfuscated
Next steps: Take a moment to review the security alert above. Review
the linked package source code to understand the potential risk. Ensure the
package is not malicious before proceeding. If you're unsure how to proceed,
reach out to your security team or ask the Socket team for help at
support@socket.dev.
Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.
Mark the package as acceptable risk. To ignore this alert only
in this pull request, reply with the comment
@SocketSecurity ignore pypi/llama-cpp-python@0.3.31. You can
also ignore all packages with @SocketSecurity ignore-all.
To ignore an alert for all future pull requests, use Socket's Dashboard to
change the triage state of this alert.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
>=1.19.0,<2.0→>=1.20.1,<2.0>=0.3.30→>=0.3.31>=9.1.0→>=9.1.1>=0.15.17→>=0.15.18>=0.0.50→>=0.0.51Release Notes
huggingface/huggingface_hub (huggingface-hub)
v1.20.1Compare Source
v1.20.0: [v1.20.0] Browser-based OAuth login, multi-commit folder uploads, and moreCompare Source
🔒 Browser-based OAuth login
hf auth loginnow defaults to a browser-based OAuth Device Code flow instead of asking you to copy-paste a token. The command prints a URL and a short code, you authorize in the browser, and the CLI retrieves and saves the token for you. The same applies tologin()in Python. In an interactive terminal you still get agh-style arrow-key menu to pick between browser login and pasting a token, and--tokenworks exactly as before.OAuth tokens expire after 30 days, but they come with a refresh token:
get_token()transparently refreshes them when less than a day of validity remains, so long-running setups keep working without re-authenticating.hf auth listnow shows the expiry date for OAuth tokens.When the command is run by an AI agent, it never prompts. Instead it streams structured events so the agent can surface the URL and code to its user, then blocks until a terminal
auth_success/auth_errorevent:hf auth listsurfaces the new expiry column:Finally,
notebook_login()now renders the link and code with plainIPython.display.HTML, dropping theipywidgetsdependency.⚡ Faster, more reliable
hf uploadfor large foldershf uploadand the underlyingupload_folderhave been revamped to be faster and far more robust on large folders. Whenhf_xetis installed (the default), uploads now run through a streamed, multi-commit pipeline built on theXetSessionAPI: the folder is scanned and fed into a background Xet upload while previous batches are committed in parallel, and files are hashed in a single read pass while they are chunked (the old flow read every large file twice). Nothing changes in how you call it:This is a drop-in replacement for experimental
hf upload-large-folderused until today, which will be deprecated in a future release.What you get on large folders:
(part N)suffix.💻 Jobs:
wait, SSH access, and cleaner error messagesThis release adds three major capabilities to Hugging Face Jobs.
Wait for completion.
HfApi.wait_for_job()andhf jobs waitblock until one or more Jobs reach a terminal stage, which makes it easy to chain commands in CI scripts.wait_for_jobaccepts a single id or a list, returns the finalJobInfoeven on failure (checkjob.status.stage), and only raisesTimeoutErroron timeout. The CLI exits0only if all waited-on Jobs endedCOMPLETED.SSH access. With
--sshat launch and an SSH key registered on huggingface.co/settings/keys, you can connect straight into a running Job's container withhf jobs ssh <job_id>. Thanks towait_for_job,hf jobs sshnow waits for the Job to reachRUNNINGbefore connecting (with a status spinner) instead of failing immediately while it is still scheduling.Readable errors. A new
JobNotFoundErrorand the switch fromresponse.raise_for_statustohf_raise_for_statusturn rawhttpxtracebacks into clean, actionable messages. Per-commandtry/exceptblocks were removed in favor of the global CLI error handling.hf jobs waitandHfApi.wait_for_jobby @Wauplin in #4345hf jobs sshwait for job to be running by @Wauplin in #4379🖥️ Custom-container deploy for Inference Endpoints
hf endpoints deploycan now deploy custom Docker containers end-to-end, no more hand-writing JSON and POSTing the raw endpoints API. New flags wire up the image and its runtime:--custom-image,--health-route,--port,--command, and--container-args. Environment variables and secrets can be injected with--env/--env-fileand--secrets/--secrets-file. On the SDK side,create_inference_endpointgainscontainer_commandandcontainer_argsparameters.hf endpoints deploy nex-n2-pro \ --repo nex-agi/Nex-N2-Pro \ --framework custom \ --accelerator gpu --vendor aws --region us-east-1 \ --instance-type nvidia-h200 --instance-size x8 \ --custom-image nexagi/sglang:v0.5.12 \ --health-route /health --port 30000 \ --container-args "--reasoning-parser qwen3 --tool-call-parser qwen3_coder --mamba-scheduler-strategy extra_buffer --tp 8" \ --env MODEL_ID=/repository \ --type authenticatedThe
typeparameter now defaults toauthenticatedinstead of the deprecatedprotected(passingprotectedemits aFutureWarning). The custom-container flags raise a clean error if used without--custom-image.⏳ Wait for a Space with
wait_for_spaceandhf spaces waitMirroring the new
wait_for_jobprimitive,HfApi.wait_for_space()andhf spaces waitblock until a Space leaves an intermediate stage (BUILDING,APP_STARTING, …) and settles on a final state. The CLI exits0if the Space isRUNNING, non-zero otherwise.hf spaces sshandhf spaces dev-modewere refactored to usewait_for_spaceinternally instead of the old CLI-only helper.📚 Documentation: CLI guide — wait for a Space · Space runtime reference
wait_for_spaceAPI andhf spaces waitCLI by @Wauplin in #4380💔 Breaking Changes
🚨🚨 With the
upload_folderandhf uploadrevamp, uploading a folder might result in multiple commits.It is also not possible to open a PR against a specific revision while using
upload_folder. If you passcreate_pr=True, it will necessarily create a PR against main. It will open the PR no matter if some changes have been committed (previously an empty commit was resulting in no PR opened at all).RepoUrlnow rejects canonical single-segment repo IDs like"gpt2"or"datasets/squad"(use"user/gpt2"or"datasets/user/squad"instead).repo_type_and_id_from_hf_idis softly deprecated.parse_hf_urigains anendpointargument to parse URLs from self-hosted Hub instances.parse_hf_uriinRepoUrl+ soft-deprecaterepo_type_and_id_from_hf_idby @Wauplin in #4324Non-detached
hf jobs run/hf jobs uv runnow exit with the Job's outcome (exit1on Job error) instead of always exiting0🖥️ CLI
createcommand instead of just reporting the 404.🔧 Other QoL Improvements
408 Request Timeoutis now part of the default retry status set, alongside the existing 5xx codes.📖 Documentation
🐛 Bug and typo fixes
error_descriptionin HTTP error messages by @coyotte508 in #4341 — failed OIDC exchanges now surface the server'serror_description, making misconfigured Trusted Publishers far easier to debug.RemoteProtocolErrorinhttp_getby @Wauplin in #4351 — transient connection drops mid-download are now retried instead of failing the download.desktop.iniand similar Windows metadata files no longer trip upscan-cache.🏗️ Internal
inferencepytest marker to filter inference tests by @Wauplin in #4338--prerelease=allowinjection for sentence-transformers by @hanouticelina in #4366abetlen/llama-cpp-python (llama-cpp-python)
v0.3.31Compare Source
f449e05pytest-dev/pytest (pytest)
v9.1.1Compare Source
pytest 9.1.1 (2026-06-19)
Bug fixes
pytest.RaisesGroupwhich would might cause it to display incorrect "It matches FooError() which was paired with BarError" messages.list-itemtyping errors from mypy in@pytest.mark.parametrize <pytest.mark.parametrize ref>argvaluesparameter.conftest.pyfiles located in<invocation dir>/test*were no longer loaded as initial conftests when invoked without arguments.This could cause certain hooks (like
pytest_addoption) in these files to not fire.astral-sh/ruff (ruff)
v0.15.18Compare Source
Released on 2026-06-18.
Preview features
ruff:ignorecomments (#25791)pydocstyle] Prevent property docstrings starting with verbs (D421) (#23775)flake8-pyi] ExtendPYI033to Python files (#26129)Bug fixes
Rule changes
flake8-pyi] RenamePYI033tolegacy-type-comment(#26131)Performance
ThinVecfor call keywords (#25999)Server
Documentation
flake8-tidy-imports] Add fix safety section (TID252) (#17491)Parser
__debug__lambda parameters (#26022)_as a match-pattern target (#25977)yieldexpressions after commas (#26024)Playground
Contributors
astral-sh/ty (ty)
v0.0.51Compare Source
Released on 2026-06-18.
Bug fixes
Annotated[Any, ...]as a class base (#26133)LSP server
Core type checking
AnyorUnknownbases are descriptors (#26120)Diagnostics
Performance
Documentation
Contributors
Configuration
📅 Schedule: (in timezone Asia/Ho_Chi_Minh)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.
This PR was generated by Mend Renovate. View the repository job log.