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 := falseView on GitHub (pinned to 909b515798)
Solutions
- Verify the file path in the acquisition config matches an existing file (ls the exact path).
- Check read permissions for the crowdsec user on the file and its parent directories.
- 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.
- 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
- Pre-check existence/readability of glob targets before starting acquisition.
- Run crowdsec as a user with group membership in the log files' group (e.g. adm).
- Use glob patterns so acquisition picks up files as soon as they're created.
- Test acquisition config with cscli before restarting the service.
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
- unable to close %s : %s
- could not lstat() file %s: %w
- could not start tailing file %s : %w
- failed opening %s: %w
- failed to read gz %s: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/b4d98b3fffc90055.
Report an issue: GitHub.