hasura/graphql-engine · error
can't move, move target %v is not a subpath from=%q, to=%q
Error message
can't move, move target %v is not a subpath from=%q, to=%q
What it means
findMoveTargets computed a move whose source or destination is not a subpath of the allowed source/destination base directories, and isMoveAllowed rejected it. This is a security guard preventing a plugin's FileOperations from moving files outside the staging/install directories.
Source
Thrown at cli/plugins/move.go:84
return nil, errors.E(op, fmt.Errorf("could not get files using a glob string: %w", err))
}
if len(gl) == 0 {
return nil, errors.E(
op,
fmt.Errorf("no files in the plugin archive matched the glob pattern=%s", fo.From),
)
}
moves := make([]move, 0, len(gl))
for _, v := range gl {
newPath := filepath.Join(newDir, filepath.Base(filepath.FromSlash(v)))
// Check secure path
m := move{from: v, to: newPath}
if !isMoveAllowed(fromDir, toDir, m) {
return nil, errors.E(
op,
fmt.Errorf(
"can't move, move target %v is not a subpath from=%q, to=%q",
m,
fromDir,
toDir,
),
)
}
moves = append(moves, m)
}
return moves, nil
}
func getDirectMove(fromDir, toDir string, fo FileOperation) (move, bool, error) {
var (
op errors.Op = "plugins.getDirectMove"
m moveView on GitHub (pinned to 724551b9ae)
Solutions
- Audit the plugin manifest's From/To fields and remove any '..' or absolute-path segments in To
- Ensure To is a plain relative destination inside the install directory
- If you maintain the plugin index, validate FileOperations with IsSubPath before publishing
- Treat unexpected occurrences as a red flag: the plugin index may be tampered with — reinstall from the official index
Example fix
// before To: "../ escape/bin" // after To: "bin"
Defensive patterns
Strategy: validation
Validate before calling
_, okFrom := plugins.IsSubPath(fromDir, filepath.Join(fromDir, filepath.FromSlash(fo.From)))
_, okTo := plugins.IsSubPath(toDir, filepath.Join(toDir, filepath.FromSlash(fo.To)))
if !okFrom || !okTo {
return errors.New("FileOperation escapes allowed directories")
} Try / catch
if err := moveFiles(...); err != nil && strings.Contains(err.Error(), "not a subpath") {
// reject/fix manifest entry; do not blindly retry
} Prevention
- Treat any subpath rejection as possible path traversal, not noise
- Validate From/To with IsSubPath before calling install APIs
- Only consume trusted plugin indexes
When it happens
Trigger: A FileOperation where the resolved destination (toDir + basename of the glob match) escapes toDir, e.g. To contains enough '..' segments to climb out, or fromDir/toDir resolution makes the joined path fall outside the base.
Common situations: Manifest To field like "../../elsewhere"; symlinks or odd relative paths in fromDir/toDir; a crafted malicious plugin index attempting path traversal.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- can't move, move target %v is out of bounds from=%q, to=%q
- the fullPath %q does not extend the sub-fullPath %q: %w
- could not get files using a glob string: %w
- no files in the plugin archive matched the glob pattern=%s
- could not find move targets: %w
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/3a32bf58aa4f4b44.
Report an issue: GitHub.