{"record":{"id":"73cee05f5a550072","repo":"crowdsecurity/crowdsec","slug":"failed-to-read-s-w","errorCode":null,"errorMessage":"failed to read %s: %w","messagePattern":"failed to read (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cwhub/sync.go","lineNumber":197,"sourceCode":"\titem := &Item{\n\t\thub:      h,\n\t\tName:     spec.fname,\n\t\tStage:    spec.stage,\n\t\tType:     spec.ftype,\n\t\tFileName: fileName,\n\t\tState: ItemState{\n\t\t\tLocalPath: path,\n\t\t\tlocal:     true,\n\t\t\tUpToDate:  true,\n\t\t},\n\t}\n\n\t// try to read the name from the file\n\titemName := localItemName{}\n\n\titemContent, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read %s: %w\", path, err)\n\t}\n\n\terr = yaml.Unmarshal(itemContent, &itemName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse %s: %w\", path, err)\n\t}\n\n\tif itemName.Name != \"\" {\n\t\titem.Name = itemName.Name\n\t}\n\n\treturn item, nil\n}\n\n// ErrSkipPath is a sentinel to skip regular files because \"nil, nil\" is ambiguous. Returning SkipDir with files would skip the rest of the directory.\nvar ErrSkipPath = errors.New(\"sentinel\")\n\nfunc (h *Hub) itemVisit(path string, f os.DirEntry, err error) (*itemSpec, error) {","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/cwhub/sync.go#L179-L215","documentation":"newLocalItem reads a local item file from disk to extract an optional 'name' field from its yaml front matter. If os.ReadFile fails (missing file, permission problem, path is a directory), the underlying OS error is wrapped in 'failed to read %s' and the item cannot be registered during hub sync.","triggerScenarios":"syncDir/addItemFromSpec references a path that no longer exists (deleted between listing and reading), or is unreadable by the user running crowdsec (root-only permissions), or is a directory/special file.","commonSituations":"Permissions tightened on /etc/crowdsec after running cscli as root then crowdsec as another user; broken symlinks left behind after uninstalls; race with an editor that deletes and recreates config files.","solutions":["Check the file exists: ls -l <path>; restore it or remove stale references/symlinks","Fix permissions so the user running crowdsec can read it (chmod/chown)","If the path is a directory or non-regular file, move it out of the scanned config directory"],"exampleFix":"// before\ncscli hub item install crowdsecurity/ssh_bf -t scenarios  # run as root, files 0600 root:root\n# crowdsec service runs as 'crowdsec' user and cannot read them\n// after\nchown -R crowdsec:crowdsec /etc/crowdsec/\nchmod -R u+r /etc/crowdsec/","handlingStrategy":"try-catch","validationCode":"import \"os\"\n\nfunc readable(path string) error {\n\tinfo, err := os.Stat(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !info.Mode().IsRegular() {\n\t\treturn fmt.Errorf(\"%s is not a regular file\", path)\n\t}\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn f.Close()\n}","typeGuard":null,"tryCatchPattern":"if err := hub.Load(ctx); err != nil {\n\tif errors.Is(err, os.ErrPermission) || errors.Is(err, os.ErrNotExist) {\n\t\tlog.Warnf(\"local item unreadable, skipping: %v\", err)\n\t\treturn nil\n\t}\n\treturn err\n}","preventionTips":["Run cscli and crowdsec as the same user (or chown -R crowdsec:crowdsec /etc/crowdsec)","Keep config file permissions at least group/others-readable for the service user","Clean up broken symlinks after uninstalling items"],"tags":["filesystem","file-read","permissions","crowdsec"],"backgroundTag":"file-read-failed","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"}