unslothai/unsloth · error · RuntimeError
GGUF conversion produced a symlinked Modelfile, refusing to
Error message
GGUF conversion produced a symlinked Modelfile, refusing to relocate it: {modelfile} What it means
RuntimeError raised when the Modelfile found among the conversion outputs is a symlink and is about to be relocated into the save directory. Unlike a failed Modelfile move (which is only a warning because the Modelfile is optional), a symlinked Modelfile is refused outright: moving it could follow the link and place unintended content into the user's save directory.
Source
Thrown at studio/backend/core/export/export.py:1194
for src in sorted(produced):
if src.is_symlink():
raise RuntimeError(
f"GGUF conversion produced a symlink, refusing to relocate it: {src}"
)
dest = os.path.join(abs_save_dir, src.name)
shutil.move(str(src), dest)
relocated_ggufs.append(dest)
logger.info(f"Relocated GGUF: {src.name} → {abs_save_dir}/")
if not relocated_ggufs:
raise RuntimeError(
"GGUF conversion produced no files: no .gguf outputs for "
f"{abs_save_dir}"
)
if modelfiles:
modelfile = sorted(modelfiles)[0]
if modelfile.is_symlink():
raise RuntimeError(
"GGUF conversion produced a symlinked Modelfile, "
f"refusing to relocate it: {modelfile}"
)
# Optional artifact: unsloth generates it best-effort, so a locked or
# read-only destination must not fail an export whose GGUFs all landed.
try:
shutil.move(str(modelfile), os.path.join(abs_save_dir, "Modelfile"))
logger.info(f"Relocated Modelfile → {abs_save_dir}/")
except OSError as exception:
logger.warning(f"Could not relocate the Modelfile: {exception}")
finally:
# Preserve any GGUF that could not be relocated. The imatrix is an input,
# so counting it would retain the merged checkpoint on every such export.
unrelocated = []
if model_tmp_path.is_dir():
unrelocated = sorted(
str(p)
for p in model_tmp_path.rglob("*.gguf")View on GitHub (pinned to 203007d190)
Solutions
- Inspect the symlink target (readlink) and replace the link with a real copy of the Modelfile in the temp dir, then re-export.
- Disable whatever layer is creating links in the export temp tree (cache dedup options, mount style).
- Note the GGUFs may have already been relocated successfully; only the Modelfile step aborts — fixing the link and re-running completes it.
Example fix
# diagnose readlink -f /tmp/.../Modelfile cp --remove-destination "$(readlink -f /tmp/.../Modelfile)" /tmp/.../Modelfile # then re-run the export
Defensive patterns
Strategy: validation
Validate before calling
mf = next(Path(model_tmp).rglob('Modelfile'), None)
if mf is not None and mf.is_symlink():
replace_link_with_copy(mf) Try / catch
try:
export()
except RuntimeError as e:
if 'symlinked Modelfile' in str(e):
replace_link_with_copy(modelfile_path); export() # GGUFs may already be relocated Prevention
- Treat any symlink in converter output as a defect and materialize real files.
- Keep export temp trees on plain directories, not linked caches.
When it happens
Trigger: The converter or a wrapper emitting Modelfile as a symlink into the temp dir; shared caches linking template Modelfiles; storage layers that materialize small files as links.
Common situations: Same environments as the GGUF-symlink case: containerized exports with symlinked caches, deduplicating filesystems, or converters that link boilerplate Modelfiles from templates.
Related errors
- GGUF conversion produced a symlink, refusing to relocate it:
- GGUF conversion produced no files: no .gguf outputs for {abs
- A transformers installation is replacing the latest sidecar;
- Subprocess error: {error_msg}
- Timeout waiting for '{expected_type}' response after {timeou
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/647a8626e2f842e6.
Report an issue: GitHub.