Skip to content

fix(runtime): finalize HF model download (create snapshot symlink) — fixes model-not-found on every binary - #47

Merged
SnowCheetos merged 1 commit into
mainfrom
fix/hf-model-finalize
Jul 8, 2026
Merged

fix(runtime): finalize HF model download (create snapshot symlink) — fixes model-not-found on every binary#47
SnowCheetos merged 1 commit into
mainfrom
fix/hf-model-finalize

Conversation

@SnowCheetos

Copy link
Copy Markdown
Contributor

Critical: HF model download is broken in every shipped binary

Any run that downloads a model from Hugging Face fails at warmup:

runtime warmup failed: embedding error: embedding model not found after resolution:
.../models--ggml-org--Qwen3-1.7B-GGUF/snapshots/<rev>/Qwen3-1.7B-Q4_K_M.gguf

The download succeeds — the full GGUF blob lands in blobs/<sha> — but the resolved path (snapshots/<rev>/<file>) is a symlink that never gets created, so ModelHandle::load's path.exists() check fails.

Root cause

resolve_hf_model in the bridge does:

auto plan = common_download_get_hf_plan(model, opts);
common_download_run_tasks({ common_download_task(plan.primary, opts) });   // writes blobs/<sha>
model.path = plan.primary.final_path… ;                                    // ← dangling snapshot path

Since b9837, writing the blob and creating the snapshots/<rev>/<file> → ../../blobs/<sha> symlink are separate steps. The symlink + path selection is done by the public hf_cache::finalize_file() (hf-cache.cpp). llama.cpp's own common/arg.cpp does get_hf_plan → run_tasks → finalize_file; the bridge skipped that last step.

Fix

Call hf_cache::finalize_file(plan.primary) after the download and use its return value — it creates the snapshot symlink (or returns the blob path directly if symlinks are unavailable) and hands back the path to load. Exactly mirrors upstream arg.cpp.

+#include "hf-cache.h"
 ...
-model.path = plan.primary.final_path.empty() ? plan.primary.local_path : plan.primary.final_path;
+model.path = hf_cache::finalize_file(plan.primary);

Verification

  • Bridge compiles against a real b9837 checkout in both prebuilt and source modes; finalize_file resolves from hf-cache.h.
  • Confirmed the failure mode on-box: the blob was a valid GGUF (GGUF magic) sitting in blobs/ with an empty snapshots/; manually creating the exact symlink finalize_file would make lets the resolved path load.

Impact / merge priority

This affects every backend, including the released prebuilt binaries — HF --hf-repo downloads (the default onboarding path via autocommit init) are broken without it. Worth merging ahead of a v0.17.6 tag.

Downloading a model from Hugging Face left the blob in the cache but the
resolved path dangling, so every run failed at warmup with:

    embedding model not found after resolution:
    .../snapshots/<rev>/<model>.gguf

resolve_hf_model called common_download_get_hf_plan + common_download_run_tasks
(which writes the blob to blobs/<sha>) but never called hf_cache::finalize_file
— the function that creates the snapshots/<rev>/<file> -> ../../blobs/<sha>
symlink and returns the usable path. llama.cpp's own common/arg.cpp does
get_hf_plan -> run_tasks -> finalize_file; the bridge skipped the last step (a
b9837 change split the snapshot bookkeeping out of run_tasks).

Call hf_cache::finalize_file(plan.primary) after the download and use its
return value: it creates the snapshot symlink, or returns the blob path
directly if symlinks are unavailable. This affects every backend, including
the shipped prebuilt binaries — HF model download was broken for all of them.

Verified: the bridge compiles against b9837 in both prebuilt and source modes,
and finalize_file resolves from hf-cache.h.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 8, 2026 05:04

Copilot AI 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.

Pull request overview

Fixes Hugging Face model downloads in the llama.cpp bridge by ensuring the resolved snapshot path is actually materialized after downloading (preventing “model not found after resolution” failures in warmup for shipped binaries).

Changes:

  • Include llama.cpp’s HF cache API header (hf-cache.h) in the bridge.
  • After common_download_run_tasks, call hf_cache::finalize_file(plan.primary) and use its returned path as the load path (creating the snapshots/<rev>/<file> -> ../../blobs/<sha> symlink when supported).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@SnowCheetos
SnowCheetos merged commit a927210 into main Jul 8, 2026
9 checks passed
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