googleapis/mcp-toolbox · error

path %q cannot be resolved: %w

Error message

path %q cannot be resolved: %w

What it means

ResolveWithinDir verifies that a user-supplied relative path stays inside an allowed directory after symlink resolution. This error is returned when the destination path cannot be resolved via filepath.EvalSymlinks/ResolveSymlinks (e.g. broken symlink, permission failure, path not existing in a way EvalSymlinks rejects). The underlying OS error is wrapped with %w so the root cause (ENOENT, EACCES, ELOOP) is preserved.

Source

Thrown at internal/tools/cloudstorage/cloudstoragecommon/paths.go:152

	cleanDest := filepath.Clean(filepath.Join(cleanDir, rel))
	out, err := escapes(cleanDir, cleanDest)
	if err != nil {
		return "", fmt.Errorf("path %q cannot be resolved within %q: %w", rel, cleanDir, err)
	}
	if out {
		return "", fmt.Errorf("path %q escapes configured directory %q", rel, cleanDir)
	}

	// Repeat the check against the real targets. A symlink under cleanDir can
	// point anywhere, so the name-level check above proves nothing on its own.
	resolvedDir, err := ResolveSymlinks(cleanDir)
	if err != nil {
		return "", fmt.Errorf("directory %q cannot be resolved: %w", cleanDir, err)
	}
	resolvedDest, err := ResolveSymlinks(cleanDest)
	if err != nil {
		return "", fmt.Errorf("path %q cannot be resolved: %w", rel, err)
	}
	out, err = escapes(resolvedDir, resolvedDest)
	if err != nil {
		return "", fmt.Errorf("path %q cannot be resolved within %q: %w", rel, cleanDir, err)
	}
	if out {
		return "", fmt.Errorf("path %q resolves through a symbolic link to a target outside configured directory %q", rel, cleanDir)
	}
	return cleanDest, nil
}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the wrapped %w cause with errors.Unwrap/errors.Is to identify the OS error (ENOENT/EACCES/ELOOP)
  2. Remove or repair the dangling symlink at the destination path
  3. Ensure the process has read+execute permission on every directory component of the path
  4. Re-check the path with `ls -la` / `readlink -f` on the host before retrying

Example fix

// before
resolvedDest, err := ResolveSymlinks(cleanDest) // fails: dangling symlink
// after
if _, err := os.Lstat(cleanDest); err == nil {
    if fi, err := os.Stat(cleanDest); err != nil && os.IsNotExist(err) {
        os.Remove(cleanDest) // remove dangling symlink before resolving
    }
}
resolvedDest, err := ResolveSymlinks(cleanDest)
Defensive patterns

Strategy: validation

Validate before calling

func pathResolvable(p string) error {
    if _, err := filepath.EvalSymlinks(p); err != nil {
        return fmt.Errorf("path %q not resolvable: %w", p, err)
    }
    return nil
}
if err := pathResolvable(dest); err != nil { return err }

Type guard

func isSymlink(p string) bool {
    fi, err := os.Lstat(p)
    return err == nil && fi.Mode()&os.ModeSymlink != 0
}

Try / catch

resolved, err := ResolveWithinDir(baseDir, userPath)
if err != nil {
    var perr *os.PathError
    if errors.As(err, &perr) { log.Printf("OS cause: %v", perr.Err) }
    return fmt.Errorf("invalid destination: %w", err)
}

Prevention

When it happens

Trigger: Calling ResolveWithinDir (directly or via a cloud-storage tool's Invoke) with a 'dest' path containing a dangling symlink or an unreadable path component so ResolveSymlinks(cleanDest) returns an error.

Common situations: User provides a destination object path that includes a symlink pointing to a deleted file; running as a service account lacking execute permission on a directory component; container volumes with stale symlinks after a restart.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/aea61c48e85f1c04. Report an issue: GitHub.