crowdsecurity/crowdsec · error

unable to read %s : %s

Error message

unable to read %s : %s

What it means

CrowdSec's file streaming acquisition calls setupTailForFile to begin tailing a log file. Before setting up the tail, it opens the file with os.Open to verify it is readable; if that open fails, it wraps the OS error in "unable to read %s : %s". It means the acquisition module cannot access the file at all (it doesn't exist, permissions deny, or path issues).

Source

Thrown at pkg/acquisition/modules/file/run.go:213

		return nil
	}

	// Check if we're already tailing
	s.tailMapMutex.RLock()

	if s.tails[file] {
		s.tailMapMutex.RUnlock()
		logger.Debugf("Already tailing file %s, not creating a new tail", file)

		return nil
	}

	s.tailMapMutex.RUnlock()

	// Validate file
	fd, err := os.Open(file)
	if err != nil {
		return fmt.Errorf("unable to read %s : %s", file, err)
	}

	if err = fd.Close(); err != nil {
		return fmt.Errorf("unable to close %s : %s", file, err)
	}

	fi, err := os.Stat(file)
	if err != nil {
		return fmt.Errorf("could not stat file %s : %w", file, err)
	}

	if fi.IsDir() {
		logger.Warnf("%s is a directory, ignoring it.", file)
		return nil
	}

	// Determine polling mode
	pollFile := false

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify the file path in the acquisition config matches an existing file (ls the exact path).
  2. Check read permissions for the crowdsec user on the file and its parent directories.
  3. If the file may not exist yet, rely on the glob/pattern matching and ensure the producer creates it, or configure the module to tolerate missing files.
  4. Run crowdsec in the foreground with verbose logging to see the underlying OS error (ENOENT vs EACCES).

Example fix

// before
cat /var/log/missing.log  # No such file
# after
ls -l /var/log/myapp.log && sudo usermod -aG adm crowdsec  # grant group read
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
function canReadTailFile(path) {
  try { fs.accessSync(path, fs.constants.R_OK); return true; } catch { return false; }
}

Prevention

When it happens

Trigger: os.Open(file) returns an error during setupTailForFile, called from StreamingAcquisition startup or checkAndTailFile when a new file appears matching the acquisition pattern.

Common situations: Log file doesn't exist yet at startup; the crowdsec process runs as a non-root user lacking read permission; path typos in acquis.yaml; the file was rotated/deleted between glob match and open.

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