crowdsecurity/crowdsec · error
unable to symlink postoverflow '%s' to '%s': %w
Error message
unable to symlink postoverflow '%s' to '%s': %w
What it means
After copying the item into the runtime hub, installPostoverflowItem creates a symlink from the runtime parser/postoverflow directory to the hub copy. If os.Symlink fails for a reason other than the link already existing, the error is wrapped with both paths. An existing symlink is tolerated (os.IsExist check).
Source
Thrown at pkg/hubtest/postoverflow.go:40
// runtime/postoverflows/s00-enrich
itemTypeDirDest := fmt.Sprintf("%s/postoverflows/%s/", t.RuntimePath, item.Stage)
if err := createDirs([]string{hubDirPostoverflowDest, itemTypeDirDest}); err != nil {
return err
}
// runtime/hub/postoverflows/s00-enrich/crowdsecurity/rdns.yaml
hubDirPostoverflowPath := filepath.Join(hubDirPostoverflowDest, sourceFilename)
if err := Copy(sourcePath, hubDirPostoverflowPath); err != nil {
return fmt.Errorf("unable to copy '%s' to '%s': %w", sourcePath, hubDirPostoverflowPath, err)
}
// runtime/postoverflows/s00-enrich/rdns.yaml
postoverflowDirParserPath := filepath.Join(itemTypeDirDest, sourceFilename)
if err := os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath); err != nil {
if !os.IsExist(err) {
return fmt.Errorf("unable to symlink postoverflow '%s' to '%s': %w", hubDirPostoverflowPath, postoverflowDirParserPath, err)
}
}
return nil
}
func (t *HubTestItem) installPostoverflowCustomFrom(postoverflow string, customPath string) (bool, error) {
// we check if its a custom postoverflow
customPostOverflowPath := filepath.Join(customPath, postoverflow)
if _, err := os.Stat(customPostOverflowPath); os.IsNotExist(err) {
return false, nil
}
customPostOverflowPathSplit := strings.Split(customPostOverflowPath, "/")
customPostoverflowName := customPostOverflowPathSplit[len(customPostOverflowPathSplit)-1]
// because path is postoverflows/<stage>/<author>/parser.yaml and we wan't the stage
customPostoverflowStage := customPostOverflowPathSplit[len(customPostOverflowPathSplit)-3]
View on GitHub (pinned to 909b515798)
Solutions
- Ensure the itemTypeDirDest directory exists before install (check earlier MkdirAll results)
- Remove the stale non-symlink file at the destination path and re-run
- On Windows, run with privileges or enable developer mode for symlink support
- Check the wrapped error (EACCES/ENOENT) and fix the underlying path/permission issue
Example fix
// before
if err := os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath); err != nil {
return fmt.Errorf("unable to symlink postoverflow '%s' to '%s': %w", ...)
}
// after
_ = os.Remove(postoverflowDirParserPath)
if err := os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath); err != nil {
return fmt.Errorf("unable to symlink postoverflow '%s' to '%s': %w", ...)
} Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := os.Stat(filepath.Dir(linkPath)); err != nil {
return fmt.Errorf("symlink parent missing: %w", err)
}
if fi, err := os.Lstat(linkPath); err == nil && fi.Mode()&os.ModeSymlink == 0 {
os.Remove(linkPath) // stale non-symlink file
} Try / catch
if err := t.installPostoverflow(item); err != nil {
if strings.Contains(err.Error(), "unable to symlink") && runtime.GOOS == "windows" {
return fmt.Errorf("symlinks need admin/developer mode on windows: %w", err)
}
return err
} Prevention
- Create all destination directories before symlinking
- Clean stale destination paths before install
- On Windows CI, enable developer mode or use copies instead of symlinks
When it happens
Trigger: os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath) fails: parent directory of the symlink target doesn't exist, permission denied, or on Windows where symlink creation requires privileges.
Common situations: Runtime postoverflow stage directory not created before symlinking; running hub tests on Windows without developer mode/privileges; stale file at the symlink destination that is not a symlink.
Understand the failure class
Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.
Related errors
- unable to symlink parser '%s' to '%s': %w
- too many levels of symbolic links
- failed to stat %s: %w
- while creating symlink from %s to %s: %w
- unable to symlink appsec-rule '%s' to '%s': %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/7b5b06d2fa33fc11.
Report an issue: GitHub.