Summary
qmd doctor reports a revision-pinned Hugging Face model as missing from the model cache even when node-llama-cpp resolves the same full URI from that cache with download: false.
Observed with @tobilu/qmd 2.8.3 and Node 24.20.0 on macOS. The same filename-matching code is present on main at the time of this report.
Minimal offline reproduction
Run from a QMD checkout with dependencies installed. The four-byte file is a synthetic fixture for the cache lookup: QMD's current inspectGgufFile regards a file beginning with GGUF as valid for this diagnostic. No model is downloaded or loaded.
repro_root=$(mktemp -d)
qmd_binary="$(pwd)/bin/qmd"
model_uri='hf:example/model/fixture.gguf#0123456789abcdef0123456789abcdef01234567'
mkdir -p "$repro_root/project/.qmd" "$repro_root/cache/qmd/models"
cat > "$repro_root/project/.qmd/index.yml" <<YAML
models:
embed: $model_uri
generate: $model_uri
rerank: $model_uri
YAML
printf 'GGUF' > "$repro_root/cache/qmd/models/hf_example_model_0123456789abcdef0123456789abcdef01234567_fixture.gguf"
node --input-type=module -e '
import { resolveModelFile } from "node-llama-cpp";
const found = await resolveModelFile(process.argv[1], {
directory: process.argv[2], download: false, cli: false
});
console.log(found);
' "$model_uri" "$repro_root/cache/qmd/models"
(
cd "$repro_root/project"
XDG_CACHE_HOME="$repro_root/cache" QMD_TRUST_LOCAL_CONFIG=1 QMD_DOCTOR_DEVICE_PROBE=0 NO_COLOR=1 "$qmd_binary" doctor
)
The offline resolver returns the existing file. qmd doctor exits 0 and prints:
⚠ model cache: missing 1/1: embedding+generation+reranking: hf:example/model/fixture.gguf#0123456789abcdef0123456789abcdef01234567. Next: run `qmd pull`
I also repeated this with three real GGUF blobs under the exact filenames required by the offline resolver for three distinct revision-pinned URIs. All three resolved with download: false and began with the GGUF magic; qmd doctor still reported missing 3/3. The cache directory inventory was unchanged by doctor.
Reproduction after an actual qmd pull
I also tested a fresh download into an empty, isolated cache with the 1.8 MB shibatch/tiny1m GGUF. All three roles use the same pinned URI so only one file needs downloading:
repro_root=$(mktemp -d)
qmd_binary="$(pwd)/bin/qmd"
model_uri='hf:shibatch/tiny1m/tiny1m.F16.gguf#dac47035fa06aa22cd694b67b8b744fd24e56ec3'
mkdir -p "$repro_root/project/.qmd" "$repro_root/cache" "$repro_root/home" "$repro_root/config"
cat > "$repro_root/project/.qmd/index.yml" <<YAML
models:
embed: $model_uri
generate: $model_uri
rerank: $model_uri
collections: {}
YAML
(
cd "$repro_root/project"
export HOME="$repro_root/home" XDG_CACHE_HOME="$repro_root/cache"
export QMD_CONFIG_DIR="$repro_root/config" QMD_TRUST_LOCAL_CONFIG=1 NO_COLOR=1
"$qmd_binary" update
"$qmd_binary" pull
QMD_DOCTOR_DEVICE_PROBE=0 "$qmd_binary" doctor
)
qmd pull exited 0 and placed a 1,886,272-byte GGUF in the previously empty cache under hf_shibatch_tiny1m_dac47035fa06aa22cd694b67b8b744fd24e56ec3_tiny1m.F16.gguf. The same URI resolved from that cache with resolveModelFile(..., {download: false}). Immediately afterward, qmd doctor exited 0 and reported ⚠ model cache: missing 1/1 and suggested running qmd pull again. This confirms the mismatch also occurs after a real download through QMD, not only with hand-placed files.
Likely cause
findCachedModelInspection takes model.split("/").pop() as filename and requires a cache entry to both contain that string and end in .gguf. For a URI ending in .gguf#<revision>, filename includes the revision fragment, while the resolved cache filename places the revision before the GGUF filename. The substring check cannot find that entry. See findCachedModelInspection in v2.8.3.
Could doctor use a read-only lookup that follows the same full-URI cache identity as model resolution, including the revision? The check should remain offline and should not download or alter cached models.
Summary
qmd doctorreports a revision-pinned Hugging Face model as missing from the model cache even whennode-llama-cppresolves the same full URI from that cache withdownload: false.Observed with
@tobilu/qmd2.8.3 and Node 24.20.0 on macOS. The same filename-matching code is present onmainat the time of this report.Minimal offline reproduction
Run from a QMD checkout with dependencies installed. The four-byte file is a synthetic fixture for the cache lookup: QMD's current
inspectGgufFileregards a file beginning withGGUFas valid for this diagnostic. No model is downloaded or loaded.The offline resolver returns the existing file.
qmd doctorexits 0 and prints:I also repeated this with three real GGUF blobs under the exact filenames required by the offline resolver for three distinct revision-pinned URIs. All three resolved with
download: falseand began with theGGUFmagic;qmd doctorstill reportedmissing 3/3. The cache directory inventory was unchanged bydoctor.Reproduction after an actual
qmd pullI also tested a fresh download into an empty, isolated cache with the 1.8 MB
shibatch/tiny1mGGUF. All three roles use the same pinned URI so only one file needs downloading:qmd pullexited 0 and placed a 1,886,272-byte GGUF in the previously empty cache underhf_shibatch_tiny1m_dac47035fa06aa22cd694b67b8b744fd24e56ec3_tiny1m.F16.gguf. The same URI resolved from that cache withresolveModelFile(..., {download: false}). Immediately afterward,qmd doctorexited 0 and reported⚠ model cache: missing 1/1and suggested runningqmd pullagain. This confirms the mismatch also occurs after a real download through QMD, not only with hand-placed files.Likely cause
findCachedModelInspectiontakesmodel.split("/").pop()asfilenameand requires a cache entry to both contain that string and end in.gguf. For a URI ending in.gguf#<revision>,filenameincludes the revision fragment, while the resolved cache filename places the revision before the GGUF filename. The substring check cannot find that entry. SeefindCachedModelInspectionin v2.8.3.Could
doctoruse a read-only lookup that follows the same full-URI cache identity as model resolution, including the revision? The check should remain offline and should not download or alter cached models.