dagger/dagger · error

failed to resolve target path %s: %w

Error message

failed to resolve target path %s: %w

What it means

copyFile calls c.destPathResolver(target) to map the destination path to its real (host) path before os.Link. A resolver failure is wrapped as "failed to resolve target path %s". Like the source resolver error, it indicates the destination could not be mapped to a real path the linker can use.

Source

Thrown at internal/fsutil/copy/copy_linux.go:93

		switch {
		case err == nil:
			// destination already exists, remove it
			if removeErr := os.Remove(target); removeErr != nil {
				return false, fmt.Errorf("failed to remove existing destination file %s: %w", target, removeErr)
			}
		case errors.Is(err, os.ErrNotExist):
			// destination does not exist, proceed
		default:
			return false, fmt.Errorf("failed to stat destination file %s: %w", target, err)
		}

		realSource, err := c.sourcePathResolver(source)
		if err != nil {
			return false, fmt.Errorf("failed to resolve source path %s: %w", source, err)
		}
		realTarget, err := c.destPathResolver(target)
		if err != nil {
			return false, fmt.Errorf("failed to resolve target path %s: %w", target, err)
		}

		err = os.Link(realSource, realTarget)
		switch {
		case err == nil:
			return true, nil
		case errors.Is(err, unix.EXDEV), errors.Is(err, syscall.EMLINK):
			// either crossing filesystem boundary or too many links, fallback to copy
			slog.ExtraDebug("hardlink failed, falling back to copy", "source", source, "target", target, "error", err)
		default:
			return false, fmt.Errorf("failed to create hardlink from %s to %s: %w", source, target, err)
		}
	}

	src, err := os.Open(source)
	if err != nil {
		return false, errors.Wrapf(err, "failed to open source %s", source)
	}

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Ensure the destination path is inside the configured destination root.
  2. Clean the target path (filepath.Clean / avoid "..") so it stays within the destination root.
  3. Fix or correctly configure the destPathResolver for the actual destination layout.
  4. Disable the hardlink optimization to bypass path resolution entirely (plain copy is used instead).

Example fix

// before: target escapes the dest root via ..
target := filepath.Join(destRoot, "../escape", name)
// after
target := filepath.Join(destRoot, filepath.Clean(name))
Defensive patterns

Strategy: validation

Validate before calling

func withinRoot(root, p string) bool {
    rel, err := filepath.Rel(root, p)
    return err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(filepath.Separator))
}
// call before copy:
if !withinRoot(destRoot, targetPath) {
    return fmt.Errorf("target %s escapes destination root", targetPath)
}

Try / catch

if err := copier.Copy(ctx, src, dst); err != nil && strings.Contains(err.Error(), "failed to resolve target path") {
    // clean/rebase the target path inside destRoot and retry
}

Prevention

When it happens

Trigger: destPathResolver returns an error — the target path is outside the configured destination root, the path traverses symlinks that escape it, or the custom resolver callback rejects the path.

Common situations: Destination path includes a symlinked directory resolving outside the copy root; programmatically-built target strings with ".." components escaping the root; resolver misconfigured with the wrong root prefix.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/ffef43c4a1ef3471. Report an issue: GitHub.