# Why a local model path still tries to reach HuggingFace, and how to load fully offline

> Source: https://netray.co/troubleshoot/offline-model-loading-air-gapped
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: On-Prem AI Troubleshooting

## Short answer

Passing a local path to from_pretrained does not guarantee an offline load, because transformers and related libraries (tokenizers, some model configs, auto-mapping code) can still issue background network calls to check for updates, fetch a referenced remote component, or resolve auto_map entries that point back at the original HuggingFace repo. The fix is to set HF_HUB_OFFLINE=1 and TRANSFORMERS_OFFLINE=1 explicitly, use a complete local snapshot directory (not just the weights file), and verify no config field still references a remote repo ID.

## Error Title

Model loading fails offline or in an air-gapped environment despite having local files

## Error Signature

OSError: We couldn't connect to 'https://huggingface.co' to load this model and it looks like ... is not the path to a directory containing a config.json file

## Alternate Signatures

- requests.exceptions.ConnectionError: HTTPSConnectionPool(host='huggingface.co', port=443)
- ValueError: Connection error, and we cannot find the requested files in the cached path
- Model loads config from local path but still attempts a network call for a sub-component

## Category

model-loading

## Stack

- huggingface
- transformers

## Affects

Air-gapped or network-isolated environments loading models from local disk, transformers/huggingface_hub of any recent version

## Quick Fix

### Fix it in a few minutes

**Steps:**

- Set both offline environment variables before running anything: export HF_HUB_OFFLINE=1 and export TRANSFORMERS_OFFLINE=1.
- Ensure your local directory is a complete snapshot: config.json, tokenizer files, and all weight shards, not just the .safetensors files copied alone.
- Load explicitly from the local directory path, not a repo ID string, so there is no ambiguity about intending a remote lookup.
- Check config.json and tokenizer_config.json for an auto_map field referencing a remote repo ID; if present and trust_remote_code is used, that remote code fetch will still attempt a network call unless it too is fully vendored locally.
- Test the exact load call with network access physically or firewall-disabled to confirm it truly succeeds offline before shipping to the air-gapped environment.

## Symptoms

- Loading from what looks like a valid local directory still raises a connection or timeout error
- The failure only appears in the air-gapped or firewalled environment, not on a connected development machine using the identical code
- Some components (base model weights) load fine while a specific piece (a referenced processor, a remote code file, a specific config sub-field) triggers the network attempt
- The error message explicitly names huggingface.co as the unreachable host despite a local path being passed

## Causes

### HF_HUB_OFFLINE / TRANSFORMERS_OFFLINE environment variables not set, so the library still attempts to check for updates

**Likelihood:** most-common

**Explanation:** By default, huggingface_hub and transformers try to reach the Hub first to check whether cached files are up to date (an ETag/metadata check), only falling back to local cache after that attempt times out or fails, which can be slow and, in a fully air-gapped network with no DNS resolution at all, can hang or fail hard rather than falling back gracefully. Explicit offline mode skips this network check entirely and goes straight to local files.

**Fix:** Export HF_HUB_OFFLINE=1 and TRANSFORMERS_OFFLINE=1 in the environment before any Python process starts, or set them programmatically at the very top of your script before importing transformers.

**Commands:**

- export HF_HUB_OFFLINE=1
- export TRANSFORMERS_OFFLINE=1

### Local directory is an incomplete snapshot, missing config or tokenizer files that were never copied alongside the weights

**Likelihood:** common

**Explanation:** It is common to manually copy only the large weight files (.safetensors) to an air-gapped target while forgetting smaller companion files like config.json, tokenizer.json, tokenizer_config.json, special_tokens_map.json, or generation_config.json. When any of these is missing, transformers falls back to trying to fetch it remotely, which fails hard with no network available.

**Fix:** Always transfer the complete snapshot_download output directory (or use huggingface-cli download --local-dir to get one deliberately), not a hand-picked subset of files, so every file the loader might need is present locally.

**Commands:**

- huggingface-cli download org/model --local-dir ./model-snapshot

### config.json or tokenizer_config.json contains an auto_map or custom class reference pointing back at a remote repo

**Likelihood:** occasional

**Explanation:** Models using trust_remote_code often have an auto_map field in their config that maps class names to a module path within their original HuggingFace repo. Even with the weights fully local, loading such a model with trust_remote_code=True can still trigger a fetch of that referenced Python module from the remote repo unless that code has also been fully localized.

**Fix:** For trust_remote_code models bound for an air-gapped environment, download the custom Python modeling files explicitly as part of the snapshot and verify the auto_map paths resolve locally, or vendor the code into your own package entirely to remove the dependency on remote resolution.

**Commands:**

- python -c "import json; print(json.load(open('config.json')).get('auto_map'))"

### A downstream library beyond transformers itself (a tokenizer backend, an evaluation harness, a RAG embedding step) makes its own independent network call

**Likelihood:** occasional

**Explanation:** Some libraries built on top of transformers or huggingface_hub perform their own separate download or version-check calls that are not covered by TRANSFORMERS_OFFLINE alone, since that variable only affects transformers' own logic, not every library in a larger pipeline that happens to also touch the Hub.

**Fix:** Trace exactly which library and call is making the network attempt (via a traceback or by tracing socket connections) and check whether that specific library has its own offline environment variable or requires an explicit local path argument.

**Commands:**

- python -X importtime script.py 2> import_trace.log

### DNS resolution attempt itself hangs for a long time before failing, making the environment appear stalled rather than clearly erroring

**Likelihood:** rare

**Explanation:** In a fully air-gapped network with no DNS server configured at all (rather than DNS working but the destination being unreachable), a network call can hang for the full OS-level DNS timeout before failing, making an offline-mode misconfiguration look like a hang or extreme slowness rather than an immediate, clear connection error.

**Fix:** Confirm DNS and outbound network are both fully disabled or fully enabled consistently in your test environment, since a half-configured network (DNS works, TCP connect fails) produces much longer, more confusing failure modes than either state alone.

## Diagnostics

### Confirm offline mode is actually active

**Command:** python -c "import os; print(os.environ.get('HF_HUB_OFFLINE'), os.environ.get('TRANSFORMERS_OFFLINE'))"

**Interpretation:** If either prints None, that offline flag was not actually set in the process's environment, which is the most common root cause of an unexpected network attempt.

### List exactly which files are present in the local snapshot

**Command:** ls -la ./model-snapshot

**Interpretation:** Compare this file list against a complete snapshot_download of the same model on a connected machine; any missing file (especially config.json, tokenizer files, or generation_config.json) is a likely trigger for a fallback network call.

### Test the exact load with network forcibly blocked

**Command:** python -c "import socket; socket.setdefaulttimeout(1); from transformers import AutoModelForCausalLM; AutoModelForCausalLM.from_pretrained('./model-snapshot')"

**Interpretation:** A fast failure or hang here, even on a connected machine, reproduces the air-gapped failure mode locally and lets you iterate on the fix without needing access to the actual isolated environment.

## Prevention

Standardize a deployment process that always uses huggingface-cli download --local-dir (or snapshot_download) to produce a complete, verified snapshot directory, never a manual partial file copy.

Bake HF_HUB_OFFLINE=1 and TRANSFORMERS_OFFLINE=1 into the base container image or systemd unit used in air-gapped environments, so it is never accidentally left unset.

For any trust_remote_code model destined for air-gapped use, explicitly vendor its custom Python files into your own controlled location rather than depending on auto_map resolution working offline.

Test every model's full load path with network access disabled in a staging environment before shipping it to the actual air-gapped target, to catch missing files or lingering network dependencies early.

## When To Escalate

If you are regularly onboarding new models into a genuinely air-gapped environment, this stops being a per-model troubleshooting exercise and becomes a standardized ingestion pipeline: verified snapshot download, completeness check, offline-mode smoke test, then transfer. Building that pipeline once removes this entire class of failure going forward.

## Faq

### Does setting HF_HUB_OFFLINE=1 break loading from a repo ID string instead of a local path?

**Answer:** No, if the model is already fully cached locally under the standard huggingface_hub cache directory from a prior connected download, offline mode will find and use that cache when you reference the same repo ID, it simply skips the network freshness check rather than requiring a literal local directory path.

### Why does the base model load offline but a LoRA adapter or processor fails?

**Answer:** Each component (base model, adapter, image processor, tokenizer) is typically loaded via its own from_pretrained call and its own local cache entry or directory; if only the base model's snapshot was transferred to the air-gapped environment and the adapter's files were not, that specific piece will still attempt a network fetch and fail.

### Is there a way to detect all network dependencies before deploying to an air-gapped site?

**Answer:** Run your exact loading code in a staging environment with network access blocked at the firewall level (not just unset environment variables) and treat any error or hang as a dependency that needs to be resolved before the real air-gapped deployment.

### Do quantized or GGUF models have the same offline-loading concerns?

**Answer:** GGUF models loaded through llama.cpp-based tools are generally more self-contained since the tokenizer vocabulary is embedded in the file itself, reducing the number of separate companion files needed, but any wrapper library that still checks HuggingFace for model cards or metadata can introduce the same class of network dependency.

## Search terms

HF_HUB_OFFLINE, TRANSFORMERS_OFFLINE, offline model loading huggingface, air-gapped model loading error, couldn't connect to huggingface.co, load model without internet

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
