{"record":{"id":"7b5b06d2fa33fc11","repo":"crowdsecurity/crowdsec","slug":"unable-to-symlink-postoverflow-s-to-s-w","errorCode":null,"errorMessage":"unable to symlink postoverflow '%s' to '%s': %w","messagePattern":"unable to symlink postoverflow '(.+?)' to '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hubtest/postoverflow.go","lineNumber":40,"sourceCode":"\n\t// runtime/postoverflows/s00-enrich\n\titemTypeDirDest := fmt.Sprintf(\"%s/postoverflows/%s/\", t.RuntimePath, item.Stage)\n\n\tif err := createDirs([]string{hubDirPostoverflowDest, itemTypeDirDest}); err != nil {\n\t\treturn err\n\t}\n\n\t// runtime/hub/postoverflows/s00-enrich/crowdsecurity/rdns.yaml\n\thubDirPostoverflowPath := filepath.Join(hubDirPostoverflowDest, sourceFilename)\n\tif err := Copy(sourcePath, hubDirPostoverflowPath); err != nil {\n\t\treturn fmt.Errorf(\"unable to copy '%s' to '%s': %w\", sourcePath, hubDirPostoverflowPath, err)\n\t}\n\n\t// runtime/postoverflows/s00-enrich/rdns.yaml\n\tpostoverflowDirParserPath := filepath.Join(itemTypeDirDest, sourceFilename)\n\tif err := os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath); err != nil {\n\t\tif !os.IsExist(err) {\n\t\t\treturn fmt.Errorf(\"unable to symlink postoverflow '%s' to '%s': %w\", hubDirPostoverflowPath, postoverflowDirParserPath, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (t *HubTestItem) installPostoverflowCustomFrom(postoverflow string, customPath string) (bool, error) {\n\t// we check if its a custom postoverflow\n\tcustomPostOverflowPath := filepath.Join(customPath, postoverflow)\n\tif _, err := os.Stat(customPostOverflowPath); os.IsNotExist(err) {\n\t\treturn false, nil\n\t}\n\n\tcustomPostOverflowPathSplit := strings.Split(customPostOverflowPath, \"/\")\n\tcustomPostoverflowName := customPostOverflowPathSplit[len(customPostOverflowPathSplit)-1]\n\t// because path is postoverflows/<stage>/<author>/parser.yaml and we wan't the stage\n\tcustomPostoverflowStage := customPostOverflowPathSplit[len(customPostOverflowPathSplit)-3]\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/hubtest/postoverflow.go#L22-L58","documentation":"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).","triggerScenarios":"os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath) fails: parent directory of the symlink target doesn't exist, permission denied, or on Windows where symlink creation requires privileges.","commonSituations":"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.","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"],"exampleFix":"// before\nif err := os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath); err != nil {\n    return fmt.Errorf(\"unable to symlink postoverflow '%s' to '%s': %w\", ...)\n}\n// after\n_ = os.Remove(postoverflowDirParserPath)\nif err := os.Symlink(hubDirPostoverflowPath, postoverflowDirParserPath); err != nil {\n    return fmt.Errorf(\"unable to symlink postoverflow '%s' to '%s': %w\", ...)\n}","handlingStrategy":"try-catch","validationCode":"if _, err := os.Stat(filepath.Dir(linkPath)); err != nil {\n    return fmt.Errorf(\"symlink parent missing: %w\", err)\n}\nif fi, err := os.Lstat(linkPath); err == nil && fi.Mode()&os.ModeSymlink == 0 {\n    os.Remove(linkPath) // stale non-symlink file\n}","typeGuard":null,"tryCatchPattern":"if err := t.installPostoverflow(item); err != nil {\n    if strings.Contains(err.Error(), \"unable to symlink\") && runtime.GOOS == \"windows\" {\n        return fmt.Errorf(\"symlinks need admin/developer mode on windows: %w\", err)\n    }\n    return err\n}","preventionTips":["Create all destination directories before symlinking","Clean stale destination paths before install","On Windows CI, enable developer mode or use copies instead of symlinks"],"tags":["filesystem","symlink","hubtest"],"backgroundTag":"file-write-permission-denied","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}