All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.3.1] - 2026-05-21
Fixed
- Redirect-body cache corruption —
HfHub.HTTP.download_file/3no longer writes a 3xx redirect-source body to the destination file when Req follows the redirect. Previously, a307 Temporary Redirectresponse from the HF endpoint (e.g./resolve/<rev>/<path>→ CDN-side/api/resolve-cache/...) caused the cache file to become["Temporary Redirect. Redirecting to ..." ++ resolved_body], producing checksum mismatches against pinned SHA-256 descriptors. The streaming lambda now skips chunks whoseresp.statusis not in[200, 206]. Reproduced + pinned intest/hf_hub/http_test.exs: "307 redirect body is NOT persisted to the destination — only the final 200 body lands". Surfaced bymix trinity.artifact.fetchon a clean-room clone oftrinity_coordinatoragainsthttps://huggingface.co/datasets/nshkrdotcom/trinity-coordinator-adapted-qwen3-0.6b.
[0.3.0] - 2026-05-21
Fixed
- Atomic downloads and cache hardening —
HfHub.HTTP.download_file/3now streams into<destination>.incompleteand renames into place only after a successful200/206, so failed404/401/network responses no longer leave 0-byte cache poison or clobber an existing cached file.HfHub.Download.hf_hub_download/1now treats pre-existing 0-byte cache entries as corrupt and redownloads them, and failed downloads release cache locks on every exit path. - Resume streaming wire shape —
HfHub.HTTP.download_file/3withresume: truenow correctly persists the response body for both206 Partial Content(server honorsRange) and200 OK(server ignoresRangeand restarts from scratch). Previously, Req'sCollectableinto:contract silently skipped streaming for non-200 bodies, so a 206 returned:okwith zero bytes appended; combined with the new atomic-rename, that promoted to silent cache corruption. The streaming primitive is now a function-forminto:lambda that receives chunks for every status code, and truncates the prior partial bytes on the first chunk when the server responds 200 to a Range request. - Preupload preflight —
HfHub.Commit.create/3now POSTs each commit's add-operations to/api/{type}s/{repo_id}/preupload/{revision}to ask the Hub which files should ride LFS vs. regular base64. The previous local 10 MB size threshold caused small.safetensors/.bin/etc. files to be sent as base64 even when the destination repo's.gitattributestracked their extension as LFS, producing400 "Your push was rejected because it contains binary files". This is identical in shape to_fetch_upload_modesinhuggingface_hub/_commit_api.py. Callers can opt out withpreupload: falseto keep the legacy size-threshold-only fallback (used primarily by offline tests). - Commit payload wire shape —
HfHub.Commit.create/3(and thereforeupload_file/4,upload_folder/3,upload_large_folder/3,delete_file/3,delete_folder/3) now sends the canonicalContent-Type: application/x-ndjsonbody with one header line followed by one operation per line, matching_prepare_commit_payloadinhuggingface_hub/_commit_api.py. Each operation envelope is now{"key": "file" | "lfsFile" | "deletedFile" | "deletedFolder" | "copy", "value": {"path": <path_in_repo>, ...}}. The previous JSON-envelope shape silently caused the Hub to accept the request and return acommitOidwhile discarding every operation, producing an "empty" commit that left only.gitattributesin the repository. create_pris now passed as acreate_pr=1query parameter rather than as a body field, matching the Python client.- Align Git branch/tag/ref routes with Python
huggingface_hubfor namespaced repos:- preserve literal
/inrepo_idpath components; - encode branch/tag/revision segments independently;
create_tag/3now posts to/tag/{revision}with%{"tag" => tag};list_refs/2now usesinclude_prs=1for PR refs;super_squash/2now posts to/super-squash/{branch}with a message body.
- preserve literal
- Align repository-management routes used by the artifact-publishing flow:
update_settings/2andrevision_exists?/3preserve literal repo slashes;delete/2now uses Python-compatibleDELETE /api/repos/deletewith JSON body;file_exists?/3now encodesrepo_id(literal slash),revision(quote(safe="")shape), andfilename(quote()shape, preserving subpath separators), matchinghuggingface_hub.file_download.hf_hub_url.
- Eliminate URL-encoded repo slashes across every remaining surface that calls
into the HuggingFace API. The first pass fixed
Git,Commit, andRepo; this pass coversUsers,Spaces(includingduplicate/2),Discussions,AccessRequests,Collections, andOrganizations. Every module-privatedefp encode(repo_id)helper is now routed through the internal "HfHub.Path" repo-id encoder so namespaced ids never reach the Hub asorg%2Frepo. - LFS multipart upload protocol (the
Cannot PUT /api/complete_multipartbug):- Multipart detection now reads the
chunk_sizeheader (case-insensitive) instead of the wrongx-amz-meta-chunk-sizekey. Previously, files that HF wanted uploaded in parts fell through to single-partPUTagainst the completion endpoint and returned 404. - Part URL parsing now uses digit-only string keys (
"1","00001", ...) instead of the wrongx-amz-meta-part-N-urlpattern. - Completion payload now includes the required top-level
"oid"field alongside"parts", matchinghuggingface_hub/lfs.pyexactly. - Completion request now sends the LFS
Accept: application/vnd.git-lfs+jsonandContent-Type: application/vnd.git-lfs+jsonheaders. - Malformed
chunk_sizeserver responses now surface as{:error, {:malformed_response, message}}instead of crashing the caller process via a linked task EXIT. - Part-count mismatches surface as
{:error, {:multipart_upload_failed, {:part_count_mismatch, ...}}}.
- Multipart detection now reads the
- The internal LFS header reader in
HfHub.Commit.LfsUploadnow correctly reads ETags from theReq>= 0.4 response-headers map (was always returningnil, which made multipart completion latently impossible even before the protocol fix). - Prevent URL-encoded slashes in repository IDs
Internal
- Test fixtures across
commit_test.exs,commit/folder_upload_test.exs,commit/lfs_upload_test.exs,users_test.exs,spaces_test.exs,discussions_test.exs,access_requests_test.exs,collections_test.exs, andrepo_test.exsnow expect literal/between org and repo name, matching the corrected URL encoding shipped in0.2.1and extended in0.3.0. - Add
HTTP.delete/3contract test pinning that JSON bodies reach the wire, preventing future regressions on Python-compatibleDELETE /api/repos/delete. - Add
Repo.file_exists?/3contract tests for revision encoding and dataset prefix handling.
Added
- Add an internal path helper with regression tests for repo-id and path-segment encoding.
- Add user-facing guides for runtime auth config, uploads/LFS, and Git refs/tags; package them in Hex/HexDocs.
- Add configurable timeouts for LFS uploads
Changed
- Refresh all resolvable Hex dependencies to current latest versions;
decimalandranchremain constrained by upstream dependency requirements. - Rewrite README around the artifact-publishing workflow while preserving badges and SVG logo.
- Decouple library from OS environment variables
0.2.0 - 2026-01-25
Added
:progress_callbackoption inHfHub.Download.hf_hub_download/1for download progress tracking. The callback receives(bytes_downloaded, total_bytes)during download.:verify_checksumoption inHfHub.Download.hf_hub_download/1to compute SHA256 after download.:expected_sha256option inHfHub.Download.hf_hub_download/1for SHA256 verification. Returns{:error, {:checksum_mismatch, expected, actual}}if hashes don't match.HfHub.Download.compute_sha256/1to compute SHA256 hash of a file.HfHub.offline_mode?/0to check if offline mode is enabled viaHF_HUB_OFFLINE=1env var orApplication.put_env(:hf_hub, :offline, true). (is_offline_mode/0available for Python compatibility)HfHub.try_to_load_from_cache/3for cache-only file loading without network requests. Returns{:ok, path}if file is cached,{:error, :not_cached}otherwise.
0.1.3 - 2025-12-31
Added
HfHub.HTTPwrite methods:post/3,put/3,patch/3,delete/2,post_action/3- Unified error mapping for all HTTP requests
HfHub.Repomodule for repository managementcreate/2- Create new repositories (models, datasets, spaces)delete/2- Delete repositoriesupdate_settings/2- Update repository settings (visibility, gated)move/3- Move/rename repositoriesexists?/2- Check if repository existsfile_exists?/3- Check if file exists in repositoryrevision_exists?/3- Check if revision exists
HfHub.Repo.RepoUrlstruct for repository URL responsesHfHub.Commit.Operationmodule with Add, Delete, Copy operation typesHfHub.Commit.CommitInfostruct for commit responsesHfHub.Commit.create/3- Create commits with multiple operationsHfHub.Commit.upload_file/4- Upload single file (regular or LFS)HfHub.Commit.delete_file/3- Delete file from repositoryHfHub.Commit.delete_folder/3- Delete folder from repositoryHfHub.Commit.LfsUpload- Git LFS batch upload supportHfHub.Commit.upload_folder/3- Upload entire directoriesHfHub.Commit.upload_large_folder/3- Upload large directories with batchingHfHub.Commit.matches_pattern?/2- Gitignore-style pattern matching- Pattern filtering support (allow_patterns, ignore_patterns, delete_patterns)
- Concurrent LFS uploads with configurable workers (
:max_workersoption) HfHub.Gitmodule for git operationscreate_branch/3,delete_branch/3- Branch managementcreate_tag/3,delete_tag/3- Tag management (lightweight and annotated)list_refs/2- List all branches, tags, converts, and pull requestslist_commits/2- List commit historysuper_squash/2- Squash all commits (destructive)
HfHub.Git.BranchInfo,HfHub.Git.TagInfo,HfHub.Git.GitRefs,HfHub.Git.CommitInfostructsHfHub.Discussionsmodule for community interactionslist/2- List discussions with status/author filtersget/3- Get discussion details with full event historycreate/3,create_pr/3- Create discussions and pull requestscomment/4,edit_comment/5,hide_comment/4- Comment managementclose/3,reopen/3,change_status/4- Status managementmerge_pr/3- Merge pull requestsrename/4- Rename discussions
HfHub.Discussions.Discussion,HfHub.Discussions.DiscussionDetailsstructsHfHub.Discussions.Comment,HfHub.Discussions.StatusChange,HfHub.Discussions.TitleChangeevent typesHfHub.Collectionsmodule for organizing models, datasets, and spaceslist/1- List collections with owner/item/sort filtersget/2- Get collection details with itemscreate/2- Create new collections (public/private)update/2- Update collection metadata (title, description, visibility, theme)delete/2- Delete collectionsadd_item/4- Add models, datasets, spaces, or papers to collectionsupdate_item/3- Update item notes and positionsdelete_item/3- Remove items from collections
HfHub.Collections.Collection,HfHub.Collections.CollectionItemstructsHfHub.Webhooksmodule for event notificationslist/1- List all webhooks for authenticated userget/2- Get webhook details by IDcreate/2- Create new webhooks with watched repos and domainsupdate/2- Update webhook URL, watched repos, domains, or secretenable/2,disable/2- Enable/disable webhooksdelete/2- Delete webhooks
HfHub.Webhooks.WebhookInfo,HfHub.Webhooks.WatchedItemstructsHfHub.Spacesmodule for Space managementget_runtime/2- Get Space runtime informationget_variables/2- Get Space variablesadd_secret/4,delete_secret/3- Manage secretsadd_variable/4,delete_variable/3- Manage variablesrequest_hardware/3- Request hardware upgrade/downgradeset_sleep_time/3- Set auto-sleep timeoutrequest_storage/3,delete_storage/2- Manage persistent storagepause/2,restart/2- Lifecycle controlduplicate/2- Duplicate Space to new repository
HfHub.Spaces.SpaceRuntime,HfHub.Spaces.SpaceVariablestructsHfHub.InferenceEndpointsmodule for dedicated model hostinglist/1- List all inference endpointsget/2- Get endpoint by namecreate/2- Create new inference endpoint (CPU/GPU, AWS/Azure/GCP)update/2- Update endpoint configuration (scaling, model, compute)delete/2- Delete endpointpause/2,resume/2- Lifecycle controlscale_to_zero/2- Scale endpoint to zero replicas with auto-wake
HfHub.InferenceEndpoints.Endpointstruct with full endpoint detailsHfHub.InferenceEndpoints.ModelConfig,ComputeConfig,ScalingConfig,ProviderConfigstructsHfHub.AccessRequestsmodule for gated repository access managementlist_pending/2,list_accepted/2,list_rejected/2- List access requests by statusaccept/3,reject/3- Handle pending access requestscancel/3- Revoke accessgrant/3- Grant access directly without prior request
HfHub.AccessRequests.AccessRequeststruct for access request dataHfHub.Usersmodule for user profile and activity APIget/2- Get user profile by usernamelist_followers/2- List users who follow a userlist_following/2- List users a user is followinglist_liked_repos/2- List repositories liked by a userlike/2,unlike/2- Like/unlike repositorieslist_likers/2- List users who liked a repository
HfHub.Users.Userstruct for user profile dataHfHub.Organizationsmodule for organization profile APIget/2- Get organization profile by namelist_members/2- List organization members
HfHub.Users.Organizationstruct for organization profile dataHfHub.Cardsmodule for Model and Dataset card parsingload_model_card/2,load_dataset_card/2- Load cards from repositoriesparse_model_card/1,parse_dataset_card/1- Parse cards from contentcreate_model_card/1,create_dataset_card/1- Create cards from datarender/1- Render cards to markdown with YAML frontmatter
HfHub.Cards.ModelCard,HfHub.Cards.DatasetCardstructsHfHub.Cards.ModelCardData,HfHub.Cards.DatasetCardDatafor card metadataHfHub.Cards.EvalResultfor model evaluation results- YAML frontmatter extraction and parsing via
yaml_elixir
0.1.2 - 2025-12-31
Added
- Bumblebee-compatible API for seamless integration with Elixir ML pipelines
HfHub.Repository— Repository reference types ({:hf, id},{:hf, id, opts},{:local, dir})HfHub.Hub— ETag-based caching matching Bumblebee'sBumblebee.HuggingFace.HubHfHub.RepoFiles— Repository file listing with ETags for cache validation- Top-level delegations:
get_repo_files/1,cached_download/1,2,file_url/3,file_listing_url/3
HfHub.Constants— File names, headers, timeouts matching Python'shuggingface_hub.constantsHfHub.Errors— 30+ structured exception types matching Python'shuggingface_hub.errorsHfHub.LFS— LFS utilities for file hashing and upload info preparationHfHub.HTTP.head/2— HEAD requests for ETag-based cache validation
Changed
- Refactored
HfHub.DatasetFileswith extracted helper functions - Refactored
HfHub.Downloadwith extracted extraction helpers - Refactored
HfHub.HTTPwith extracted pagination helpers
0.1.1 - 2025-12-21
Added
list_repo_tree/2with pagination support viaHfHub.HTTP.get_paginated/2dataset_configs/2with fallback (dataset_infos.json + tree inference)dataset_splits/2with fallback (dataset_infos.json + tree inference)HfHub.DatasetFilesresolver for config + split file pathsHfHub.Extractfor archive extraction (zip/tar.gz/tgz/tar.xz/gz)- Optional
extract: trueflow inhf_hub_download/1
Changed
list_files/2upgraded to use tree listings for datasets/recursive mode
0.1.0 - 2025-12-20
Initial release with full HuggingFace Hub client functionality:
- HfHub.Api: Repository info, file listings, model/dataset/space queries
- HfHub.Download: File downloads with caching and resume support
- HfHub.Cache: Cache management with GenServer-based tracking
- HfHub.Auth: Token management and authentication
- HfHub.HTTP: Req-based HTTP client with retry logic
- HfHub.FS: Cache directory and file locking utilities
- HfHub.Config: Configuration with environment variable support