cjpais/Handy · error
Failed to init Hugging Face API: {}
Error message
Failed to init Hugging Face API: {} What it means
hf-hub's ApiBuilder::from_env()...build() failed inside the per-attempt download loop. build() resolves and prepares the hub cache directory (HF_HOME or ~/.cache/huggingface) and returns Err when that directory cannot be created or written. Token and endpoint config from the environment are otherwise permissive (the code explicitly passes with_token(None)).
Source
Thrown at src-tauri/src/managers/model.rs:1932
let stream_count = ATTEMPT_STREAMS[attempt - 1];
info!(
"HF download attempt {}/{} for {} using {} concurrent stream(s)",
attempt,
ATTEMPT_STREAMS.len(),
model_id,
stream_count
);
// Fresh client per attempt so a wedged connection from the previous
// try can't poison the retry.
let api = ApiBuilder::from_env()
// Ignore cached and environment-provided credentials. A stale token
// can make otherwise-public downloads fail authentication.
.with_token(None)
.with_progress(false)
.with_max_files(stream_count)
.build()
.map_err(|e| anyhow::anyhow!("Failed to init Hugging Face API: {}", e))?;
let repo = api.repo(Repo::with_revision(
repo_id.clone(),
RepoType::Model,
revision.clone(),
));
let progress = HfDownloadProgress::new(self.app_handle.clone(), model_id.clone());
// hf-hub has no internal timeouts, so a wedged connection would
// otherwise hang this attempt forever and neither the retry loop
// nor the mirror fallback would ever fire. The watchdog cancels a
// per-attempt child token when progress goes stale; a user cancel
// on the parent propagates through the same child.
let attempt_token = cancel_token.child_token();
let watchdog = tokio::spawn({
let probe = progress.clone();
let attempt_token = attempt_token.clone();
async move {
loop {View on GitHub (pinned to 98a4d80cce)
Solutions
- Set HF_HOME to a writable directory with enough space for multi-GB models
- Ensure HOME is set for whatever context launches the app (autostart .desktop, launchd, systemd)
- Check disk space and write permissions on the cache root
- If sandboxed, grant the app write access to its cache directory
Example fix
# before (service context, HOME stripped) ExecStart=/usr/bin/handy --start-hidden # after Environment=HOME=/var/lib/handy Environment=HF_HOME=/var/lib/handy/.cache/huggingface ExecStart=/usr/bin/handy --start-hidden
Defensive patterns
Strategy: validation
Validate before calling
// pre-flight the hub cache dir before entering the download loop
let cache_root = std::env::var("HF_HOME")
.map(PathBuf::from)
.unwrap_or_else(|_| {
let home = std::env::var("HOME").expect("HOME must be set for hf-hub cache");
PathBuf::from(home).join(".cache/huggingface")
});
std::fs::create_dir_all(&cache_root)
.map_err(|e| anyhow::anyhow!("hub cache {cache_root:?} not writable: {e}"))?; Try / catch
let api = match ApiBuilder::from_env().with_token(None).build() {
Ok(a) => a,
Err(e) => anyhow::bail!("cannot init HF API — check HF_HOME/HOME and disk: {e}"),
}; Prevention
- Set HF_HOME explicitly in managed launch contexts (services, autostart) to a writable dir
- Ensure HOME is present in the environment that launches the app
- Include cache-dir writability in startup diagnostics
When it happens
Trigger: HOME unset (running as a service/daemon without a login environment); HF_HOME pointing at an unwritable or nonexistent-parent path; read-only home directory; disk full; sandboxed app whose filesystem permission excludes the cache path.
Common situations: Autostart entries and window-manager launchers that strip environment variables; snap/flatpak confinement; CI runners with a read-only home; small temp disks where ~/.cache resides.
Related errors
- No model files found to delete
- {:?}
- Hugging Face download failed after {} attempt(s): {}
- threshold must be between 0.0 and 1.0
- Failed to create VAD: {e}
AI-assisted analysis of cjpais/Handy@98a4d80cce (2026-08-16).
Data as JSON: /api/errors/94fcfa1cda0ac772.
Report an issue: GitHub.