{"record":{"id":"5578d5e1fbe49437","repo":"unslothai/unsloth","slug":"gguf-conversion-produced-a-symlink-refusing-to-re","errorCode":null,"errorMessage":"GGUF conversion produced a symlink, refusing to relocate it: {src}","messagePattern":"GGUF conversion produced a symlink, refusing to relocate it: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/export/export.py","lineNumber":1178,"sourceCode":"                        quantization_method = quant_method,\n                        **imatrix_kw,\n                        **local_token_kw,\n                    )\n\n                    # Scan only the owned root; exact reported paths cover external outputs.\n                    reported = result if isinstance(result, dict) else {}\n                    produced = {p for p in model_tmp_path.rglob(\"*.gguf\") if p.is_file()}\n                    produced.update(Path(f) for f in _reported_gguf_files(result) or [])\n                    produced = {p for p in produced if not _is_imatrix(p, imatrix_path)}\n                    modelfiles = {p for p in model_tmp_path.rglob(\"Modelfile\") if p.is_file()}\n                    reported_modelfile = reported.get(\"modelfile_location\")\n                    if reported_modelfile and Path(reported_modelfile).is_file():\n                        modelfiles.add(Path(os.path.abspath(os.fspath(reported_modelfile))))\n\n                    relocated_ggufs = []\n                    for src in sorted(produced):\n                        if src.is_symlink():\n                            raise RuntimeError(\n                                f\"GGUF conversion produced a symlink, refusing to relocate it: {src}\"\n                            )\n                        dest = os.path.join(abs_save_dir, src.name)\n                        shutil.move(str(src), dest)\n                        relocated_ggufs.append(dest)\n                        logger.info(f\"Relocated GGUF: {src.name} → {abs_save_dir}/\")\n                    if not relocated_ggufs:\n                        raise RuntimeError(\n                            \"GGUF conversion produced no files: no .gguf outputs for \"\n                            f\"{abs_save_dir}\"\n                        )\n\n                    if modelfiles:\n                        modelfile = sorted(modelfiles)[0]\n                        if modelfile.is_symlink():\n                            raise RuntimeError(\n                                \"GGUF conversion produced a symlinked Modelfile, \"\n                                f\"refusing to relocate it: {modelfile}\"","sourceCodeStart":1160,"sourceCodeEnd":1196,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/export/export.py#L1160-L1196","documentation":"RuntimeError raised while relocating GGUF outputs after conversion: one of the produced .gguf paths in the temp model directory (or reported by the converter) is a symlink, and the exporter refuses shutil.move on it. Moving a symlink would either copy the link itself or follow it into the save directory, which could pull in unexpected files — so the export aborts rather than relocate untrusted link targets.","triggerScenarios":"A conversion toolchain (or a cached/converter step) emitting the .gguf as a symlink into the temp dir (e.g. hardlink/symlink deduplication in a cache); conversion running in a shared cache layout where outputs are linked rather than written; tampered or unusual converter output.","commonSituations":"Docker environments where the HF cache or temp dirs are symlinked; converters that dedupe identical outputs via links; running exports against a storage backend that materializes files as links.","solutions":["Check the reported src path: inspect what it links to (readlink) and why the converter produced a link.","Disable symlink/dedup behavior in the converter or the cache layer hosting the temp model path.","Ensure temp export directories are real directories on the same filesystem as the save dir.","If the link target is the genuine GGUF, replace the link with the real file (copy) before re-exporting."],"exampleFix":"# diagnose\nls -la /tmp/.../model/  # note the symlink\ncp --remove-destination \"$(readlink -f model_out.gguf)\" model_out.gguf  # replace link with real file\n# then re-run the export","handlingStrategy":"validation","validationCode":"symlinks = [p for p in Path(model_tmp).rglob('*.gguf') if p.is_symlink()]\nif symlinks:\n    raise/fail_fast(f'converter emitted symlinks: {symlinks}')","typeGuard":null,"tryCatchPattern":"try:\n    export()\nexcept RuntimeError as e:\n    if 'symlink' in str(e):\n        materialize_real_files(model_tmp); export()  # copy link targets over the links","preventionTips":["Run exports with real (non-symlinked) temp and cache directories.","Disable dedup/link features in converter caches.","Check converter output for links before relocation in pipelines."],"tags":["export","gguf","filesystem","symlink","studio"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}