hyperledger/fabric · error

refusing to copy absolute symlink %s -> %s

Error message

refusing to copy absolute symlink %s -> %s

What it means

copySymlink (used by CopyDir when walking external builder package contents) reads the symlink target with os.Readlink and rejects symlinks whose target is an absolute path. Absolute symlinks are considered unsafe to reproduce in the destination because they can point anywhere on the host filesystem. The copy is aborted and the destination is cleaned up.

Source

Thrown at core/container/externalbuilder/copy.go:66

	})
	// If an error occurred, clean up any created files.
	if err != nil {
		if err := os.RemoveAll(destroot); err != nil {
			logger.Errorf("failed to remove destination directory %s after copy error: %s", destroot, err)
		}
		return errors.WithMessagef(err, "failed to copy %s to %s", srcroot, destroot)
	}
	return nil
}

func copySymlink(srcroot, srcpath, destpath string) error {
	// If the symlink is absolute, then we do not want to copy it.
	symlinkDest, err := os.Readlink(srcpath)
	if err != nil {
		return err
	}
	if filepath.IsAbs(symlinkDest) {
		return errors.Errorf("refusing to copy absolute symlink %s -> %s", srcpath, symlinkDest)
	}

	// Determine where the symlink points to. If it points outside
	// of the source root, then we do not want to copy it.
	symlinkDir := filepath.Dir(srcpath)
	symlinkTarget := filepath.Clean(filepath.Join(symlinkDir, symlinkDest))
	relativeTarget, err := filepath.Rel(srcroot, symlinkTarget)
	if err != nil {
		return err
	}
	if relativeTargetElements := strings.Split(relativeTarget, string(os.PathSeparator)); len(relativeTargetElements) >= 1 && relativeTargetElements[0] == ".." {
		return errors.Errorf("refusing to copy symlink %s -> %s pointing outside of source root", srcpath, symlinkDest)
	}

	return os.Symlink(symlinkDest, destpath)
}

func copyFile(srcpath, destpath string) error {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Find and fix the offending link: 'find <srcroot> -type l -exec ls -l {} +' and rewrite it to a relative target (e.g. ln -sfn ../lib/foo foo).
  2. Remove unnecessary absolute symlinks from the chaincode package before install.
  3. Recreate the symlink at deploy/runtime (e.g. in the builder's build or release script) rather than shipping it in the source tree.
  4. If the symlink must remain, restructure directories so a relative path can express the target inside the source root.

Example fix

// before
ln -s /opt/tools/bin/cli ./bin/cli   // absolute, refused
// after
cd bin && ln -sfn ../../opt/tools/bin/cli cli   // relative target inside tree (if valid)
// or remove the symlink entirely
Defensive patterns

Strategy: validation

Validate before calling

// shell: detect absolute symlinks in a package before install
// find <pkgdir> -type l -exec readlink {} \; | grep -E '^/' && echo "absolute symlinks present" && exit 1

Try / catch

// Go caller of CopyDir
if err := CopyDir(logger, src, dst); err != nil {
    if strings.Contains(err.Error(), "refusing to copy absolute symlink") {
        // rewrite the reported link to a relative target and retry
    }
}

Prevention

When it happens

Trigger: copySymlink is invoked from the CopyDir filepath.Walk callback (anonymous walk function) on any symlink entry whose os.Readlink target begins with '/' (filepath.IsAbs true).

Common situations: Source trees checked out or built on another machine containing absolute symlinks (e.g. -> /usr/lib/somelib); symlinks created by absolute-path installs; Node.js packages vendored with machine-specific absolute links.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/113edb1b2afbad18. Report an issue: GitHub.