abiosoft/colima · error

failed to link model file: %w

Error message

failed to link model file: %w

What it means

findGGUFPath hard-links the blob into the bundle: guest.RunQuiet("docker","exec","docker-model-runner","ln",blobPath,bundlePath). ln (no -f) fails with EEXIST when a previous run already created the target file, ENOENT when the blob under /models/blobs/sha256/<hash> was garbage-collected, and EXDEV if blobs and bundles sit on different mounts.

Source

Thrown at model/docker.go:91

			if blobHash, ok := strings.CutPrefix(layer.Digest, "sha256:"); ok {
				blobPath = fmt.Sprintf("/models/blobs/sha256/%s", blobHash)
				break
			}
		}
	}

	if blobPath == "" {
		return "", fmt.Errorf("no GGUF layer found in model manifest")
	}

	// Create bundle directory and hard-link the blob (same approach as Docker Model Runner)
	bundleDir := fmt.Sprintf("/models/bundles/sha256/%s/model", modelHash)
	if err := guest.RunQuiet("docker", "exec", "docker-model-runner", "mkdir", "-p", bundleDir); err != nil {
		return "", fmt.Errorf("failed to create bundle directory: %w", err)
	}

	if err := guest.RunQuiet("docker", "exec", "docker-model-runner", "ln", blobPath, bundlePath); err != nil {
		return "", fmt.Errorf("failed to link model file: %w", err)
	}

	return bundlePath, nil
}

// InspectDockerModel returns information about a Docker model.
func InspectDockerModel(modelName string) (*DockerModelInfo, error) {
	guest := lima.New(host.New())
	output, err := guest.RunOutput("docker", "model", "inspect", modelName)
	if err != nil {
		return nil, fmt.Errorf("error inspecting model %q: %w", modelName, err)
	}

	var info DockerModelInfo
	if err := json.Unmarshal([]byte(strings.TrimSpace(output)), &info); err != nil {
		return nil, fmt.Errorf("error parsing model info: %w", err)
	}

View on GitHub (pinned to c3a5f9184d)

Solutions

  1. Remove the stale target and retry: docker exec docker-model-runner rm -f <bundlePath> (or re-serve after cleanup)
  2. Confirm the blob exists: docker exec docker-model-runner ls -l /models/blobs/sha256/<blobHash>; if missing, re-pull the model
  3. Verify /models/blobs and /models/bundles live on the same volume (docker inspect ... .Mounts) so hard links are possible
  4. Re-pull the model to restore a consistent blob+manifest+bundle set

Example fix

// before (fails with EEXIST on retry)
guest.RunQuiet("docker", "exec", "docker-model-runner", "ln", blobPath, bundlePath)

// after (idempotent link)
guest.RunQuiet("docker", "exec", "docker-model-runner", "sh", "-c",
    fmt.Sprintf("ln -f %q %q || (rm -f %q && ln %q %q)", blobPath, bundlePath, bundlePath, blobPath, bundlePath))
Defensive patterns

Strategy: validation

Validate before calling

// Make the link step idempotent: clear a stale target first.
guest.RunQuiet("docker", "exec", "docker-model-runner", "rm", "-f", bundlePath)
// ...then create the link

Try / catch

if err := guest.RunQuiet("docker", "exec", "docker-model-runner", "ln", blobPath, bundlePath); err != nil {
    // EEXIST from a stale bundle is the common retry-killer; remove and retry once
    _ = guest.RunQuiet("docker", "exec", "docker-model-runner", "rm", "-f", bundlePath)
    if err2 := guest.RunQuiet("docker", "exec", "docker-model-runner", "ln", blobPath, bundlePath); err2 != nil {
        return "", fmt.Errorf("failed to link model file: %w", err2)
    }
}

Prevention

When it happens

Trigger: A leftover bundle file from an earlier failed serve (mkdir succeeded, ln failed, then retried); blob pruned by disk cleanup between manifest read and link; runner volume split so /models/blobs and /models/bundles are on different devices.

Common situations: Retrying after an interrupted first serve; disk cleanup tools pruning blobs; nonstandard runner volume configuration.

Related errors


AI-assisted analysis of abiosoft/colima@c3a5f9184d (2026-08-15). Data as JSON: /api/errors/1007dcf23f637459. Report an issue: GitHub.