crowdsecurity/crowdsec · error

failed to stat %s : %v

Error message

failed to stat %s : %v

What it means

Wraps an os.Stat failure when loading a parser stage file during LoadStages → processStageFile. The %s is the stageFile descriptor and %v the OS error (typically 'no such file or directory' or a permission error). CrowdSec cannot even inspect the parser config file, so stage loading aborts for that path.

Source

Thrown at pkg/parser/stage.go:77

	}

	sort.Strings(pctx.Stages)
	log.Infof("Loaded %d nodes from %d stages", len(allNodes), len(pctx.Stages))

	return allNodes, nil
}

func processStageFile(stageFile Stagefile, pctx *UnixParserCtx, ectx EnricherCtx) ([]Node, error) {
	if !strings.HasSuffix(stageFile.Filename, ".yaml") && !strings.HasSuffix(stageFile.Filename, ".yml") {
		log.Warningf("skip non yaml : %s", stageFile.Filename)
		return nil, nil
	}

	log.Debugf("loading parser file '%s'", stageFile)

	st, err := os.Stat(stageFile.Filename)
	if err != nil {
		return nil, fmt.Errorf("failed to stat %s : %v", stageFile, err)
	}

	if st.IsDir() {
		return nil, nil
	}

	yamlFile, err := os.Open(stageFile.Filename)
	if err != nil {
		return nil, fmt.Errorf("can't access parsing configuration file %s : %s", stageFile.Filename, err)
	}
	defer yamlFile.Close()
	// process the yaml
	dec := yaml.NewDecoder(yamlFile)
	dec.SetStrict(true)

	var nodes []Node

	nodesCount := 0

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the printed path: does the file exist and is the symlink target intact?
  2. Reinstall/refresh the hub: `cscli hub update && cscli hub upgrade`
  3. Fix permissions on the parsers directory (readable by the crowdsec user)
  4. Correct the config path (config_dir/parsers dir) in crowdsec.yaml

Example fix

# before
ls -la /etc/crowdsec/parsers/s01-parse/ Broken -> missing_target.yaml
# after (reinstall the broken parser or remove dangling symlink)
cscli parsers remove crowdsecurity/broken-parser
cscli parsers install crowdsecurity/broken-parser
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(path)
if err != nil || info.IsDir() { return fmt.Errorf("parser file %s unreadable: %w", path, err) }

Type guard

func fileExists(p string) bool { _, err := os.Stat(p); return !os.IsNotExist(err) }

Try / catch

nodes, err := processStageFile(stageFile, pctx, ectx)
if err != nil {
    log.Warnf("skipping stage file: %v", err)
    return nil, err
}

Prevention

When it happens

Trigger: Calling processStageFile (via LoadStages) when stageFile.Filename does not exist, was removed/symlinked away, or the path is inaccessible due to permissions or a broken symlink.

Common situations: Hub partially updated leaving dangling symlinks in /etc/crowdsec/parsers/, wrong config_dir in acquis/crowdsec.yaml, running crowdsec in a container without the parsers dir mounted, permission changes on the config tree.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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