crowdsecurity/crowdsec · error

cannot copy a folder onto itself

Error message

cannot copy a folder onto itself

What it means

checkPathNotContained walks up from the destination path; if the source absolute path is an ancestor of (or equal to) the destination, copying would move a folder into itself and corrupt/lose data, so it is rejected with this error. It is called by CopyDir before any copying happens.

Source

Thrown at pkg/hubtest/utils.go:62

}

// checkPathNotContained returns an error if 'subpath' is inside 'path'
func checkPathNotContained(path string, subpath string) error {
	absPath, err := filepath.Abs(path)
	if err != nil {
		return err
	}

	absSubPath, err := filepath.Abs(subpath)
	if err != nil {
		return err
	}

	current := absSubPath

	for {
		if current == absPath {
			return errors.New("cannot copy a folder onto itself")
		}

		up := filepath.Dir(current)
		if current == up {
			break
		}

		current = up
	}

	return nil
}

// CopyDir copies the content of a directory to another directory.
// It delegates the operation to os.CopyFS with an additional check to prevent infinite loops.
func CopyDir(src string, dest string) error {
	if err := checkPathNotContained(src, dest); err != nil {
		return err

View on GitHub (pinned to 909b515798)

Solutions

  1. Choose a destination directory that is not inside the source directory
  2. Print both absolute paths and compare before running the copy
  3. If you intended an in-place move, use os.Rename instead of CopyDir
  4. Add a pre-check in the calling script using the same ancestor-walk logic

Example fix

// before: recursion attempt
CopyDir("/tmp/scenarios", "/tmp/scenarios/new")
// after: disjoint destination
CopyDir("/tmp/scenarios", "/tmp/copy-of-scenarios")
Defensive patterns

Strategy: validation

Validate before calling

func isInside(dst, src string) bool {
    absDst, _ := filepath.Abs(dst); absSrc, _ := filepath.Abs(src)
    rel, err := filepath.Rel(absSrc, absDst)
    return err == nil && rel != ".." && !strings.HasPrefix(rel, "..")+string(os.PathSeparator) && rel != "." && !strings.HasPrefix(rel, "..")
}
// call CopyDir only if !isInside(dst, src)

Try / catch

if err := CopyDir(src, dst); err != nil {
    if strings.Contains(err.Error(), "cannot copy a folder onto itself") {
        return fmt.Errorf("destination %s is inside source %s; pick another target", dst, src)
    }
    return err
}

Prevention

When it happens

Trigger: Calling CopyDir(src, dst) where dst is inside src, or dst equals src — e.g. `cscli hubtest copy . ./sub` or copying /tmp/a into /tmp/a/b.

Common situations: Shell expansion or a config variable resolving to the same directory; accidentally passing a parent folder as the destination; scripts that concatenate paths without checking containment.

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


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/5114f6e32ff822eb. Report an issue: GitHub.