{"record":{"id":"92e69f8acf72dbae","repo":"crowdsecurity/crowdsec","slug":"while-reading-symlink-w","errorCode":null,"errorMessage":"while reading symlink: %w","messagePattern":"while reading symlink: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hubops/disable.go","lineNumber":27,"sourceCode":"\n\t\"github.com/crowdsecurity/crowdsec/pkg/cwhub\"\n)\n\n// RemoveInstallLink removes the item's symlink between the installation directory and the local hub.\nfunc RemoveInstallLink(i *cwhub.Item) error {\n\tstat, err := os.Lstat(i.State.LocalPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// if it's managed by hub, it's a symlink to csconfig.GConfig.hub.HubDir / ...\n\tif stat.Mode()&os.ModeSymlink == 0 {\n\t\treturn fmt.Errorf(\"%s isn't managed by hub\", i.Name)\n\t}\n\n\ttarget, err := os.Readlink(i.State.LocalPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while reading symlink: %w\", err)\n\t}\n\n\tif target != i.State.DownloadPath {\n\t\treturn fmt.Errorf(\"%s isn't managed by hub\", i.Name)\n\t}\n\n\tif err := os.Remove(i.State.LocalPath); err != nil {\n\t\treturn fmt.Errorf(\"while removing symlink: %w\", err)\n\t}\n\n\ti.State.LocalPath = \"\"\n\n\treturn nil\n}\n\n// DisableCommand uninstalls an item and its dependencies, ensuring that no\n// sub-item is left in an inconsistent state.\ntype DisableCommand struct {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/hubops/disable.go#L9-L45","documentation":"After confirming the local path is a symlink, RemoveInstallLink reads the link target. If os.Readlink fails, the error is wrapped as 'while reading symlink: %w'. This is rare: it means the symlink disappeared between the stat and readlink, or the OS rejected the call.","triggerScenarios":"Calling RemoveInstallLink when the symlink is concurrently removed/modified, or on a filesystem that does not support readlink on that path.","commonSituations":"Concurrent cscli runs racing on the same config directory; broken filesystem state; the item file was deleted by another process between checks.","solutions":["Ensure only one cscli process modifies the config directory at a time","Re-list items ('cscli hub list') to refresh state, then retry","Reinstall the item if the state is inconsistent"],"exampleFix":"// before\nif err := RemoveInstallLink(item); err != nil { ... }\n// after\nif err := acquireConfigLock(); err != nil { return err }\ndefer releaseConfigLock()\nif err := RemoveInstallLink(item); err != nil { ... }","handlingStrategy":"validation","validationCode":"target, err := os.Readlink(item.State.LocalPath)\nif err != nil { return fmt.Errorf(\"symlink vanished: %w\", err) }","typeGuard":null,"tryCatchPattern":"if err := hubops.RemoveInstallLink(item); err != nil {\n    if errors.Is(err, fs.ErrNotExist) { /* refresh state and retry once */ }\n    return err\n}","preventionTips":["Serialize cscli operations with a lock","Re-list hub state before mutating operations","Retry once on ErrNotExist after refreshing state"],"tags":["hub","symlink","race-condition"],"backgroundTag":"file-not-found","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}