crowdsecurity/crowdsec · error

unable to read index file: %w

Error message

unable to read index file: %w

What it means

parseIndex reports failure to read the hub index file from h.local.HubIndexFile with os.ReadFile. The wrapped os error distinguishes not-exists, permission-denied, is-a-directory, etc. This makes Hub.Load fail before any JSON parsing.

Source

Thrown at pkg/cwhub/hub.go:74

	return hub, nil
}

// Load reads the state of the items on disk.
func (h *Hub) Load() error {
	h.logger.Debugf("loading hub idx %s", h.local.HubIndexFile)

	if err := h.parseIndex(); err != nil {
		return fmt.Errorf("invalid hub index: %w. Run 'sudo cscli hub update' to download the index again", err)
	}

	return h.localSync()
}

// parseIndex takes the content of an index file and fills the map of associated parsers/scenarios/collections.
func (h *Hub) parseIndex() error {
	bidx, err := os.ReadFile(h.local.HubIndexFile)
	if err != nil {
		return fmt.Errorf("unable to read index file: %w", err)
	}

	if err := json.Unmarshal(bidx, &h.items); err != nil {
		return fmt.Errorf("failed to parse index: %w", err)
	}

	// Iterate over the different types to complete the struct
	for _, itemType := range ItemTypes {
		for name, item := range h.GetItemMap(itemType) {
			if item == nil {
				// likely defined as empty object or null in the index file
				return fmt.Errorf("%s:%s has no index metadata", itemType, name)
			}

			if item.RemotePath == "" {
				return fmt.Errorf("%s:%s has no download path", itemType, name)
			}

View on GitHub (pinned to 909b515798)

Solutions

  1. Run `sudo cscli hub update` to create/download the index file
  2. Check file existence and permissions: `ls -l /var/lib/crowdsec/data/hub/.index.json`
  3. Run the command as root or fix ownership (`chown -R` the crowdsec data dir)
  4. Verify local.data_dir in config points at the directory that actually holds the index

Example fix

// before
cscli hub list   # as unprivileged user, index root-owned
// after
sudo cscli hub list
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(indexFile)
if err != nil {
    return fmt.Errorf("hub index not readable: %w — run 'cscli hub update'", err)
}
if fi.IsDir() || fi.Size() == 0 {
    return fmt.Errorf("hub index %s is not a regular non-empty file", indexFile)
}

Try / catch

if err := hub.Load(); err != nil {
    var pe *os.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrNotExist) {
        logger.Error("hub index missing; run 'sudo cscli hub update'")
        return
    }
    return err
}

Prevention

When it happens

Trigger: Hub.Load → parseIndex when the index file does not exist (no prior hub update), the path points to a directory, or the process lacks read permission.

Common situations: Fresh install without `cscli hub update`, running cscli as a non-root user against root-owned /var/lib/crowdsec, wrong config point to a custom data_dir without an index, or accidentally deleting the file.

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/5284a95924410906. Report an issue: GitHub.