crowdsecurity/crowdsec · error

failed to read %s: %w

Error message

failed to read %s: %w

What it means

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.

Source

Thrown at pkg/cwhub/sync.go:197

	item := &Item{
		hub:      h,
		Name:     spec.fname,
		Stage:    spec.stage,
		Type:     spec.ftype,
		FileName: fileName,
		State: ItemState{
			LocalPath: path,
			local:     true,
			UpToDate:  true,
		},
	}

	// try to read the name from the file
	itemName := localItemName{}

	itemContent, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("failed to read %s: %w", path, err)
	}

	err = yaml.Unmarshal(itemContent, &itemName)
	if err != nil {
		return nil, fmt.Errorf("failed to parse %s: %w", path, err)
	}

	if itemName.Name != "" {
		item.Name = itemName.Name
	}

	return item, nil
}

// ErrSkipPath is a sentinel to skip regular files because "nil, nil" is ambiguous. Returning SkipDir with files would skip the rest of the directory.
var ErrSkipPath = errors.New("sentinel")

func (h *Hub) itemVisit(path string, f os.DirEntry, err error) (*itemSpec, error) {

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the file exists: ls -l <path>; restore it or remove stale references/symlinks
  2. Fix permissions so the user running crowdsec can read it (chmod/chown)
  3. If the path is a directory or non-regular file, move it out of the scanned config directory

Example fix

// before
cscli hub item install crowdsecurity/ssh_bf -t scenarios  # run as root, files 0600 root:root
# crowdsec service runs as 'crowdsec' user and cannot read them
// after
chown -R crowdsec:crowdsec /etc/crowdsec/
chmod -R u+r /etc/crowdsec/
Defensive patterns

Strategy: try-catch

Validate before calling

import "os"

func readable(path string) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !info.Mode().IsRegular() {
		return fmt.Errorf("%s is not a regular file", path)
	}
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	return f.Close()
}

Try / catch

if err := hub.Load(ctx); err != nil {
	if errors.Is(err, os.ErrPermission) || errors.Is(err, os.ErrNotExist) {
		log.Warnf("local item unreadable, skipping: %v", err)
		return nil
	}
	return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/73cee05f5a550072. Report an issue: GitHub.