crowdsecurity/crowdsec · error

could not start tailing file %s : %w

Error message

could not start tailing file %s : %w

What it means

This is the tail.Init failure path in setupTailForFile: the hpcloud/tail library could not start following the file (given Follow, Poll, Location seekInfo options). It wraps the tail library's own error, which commonly is that the file no longer exists or can't be re-opened by the tailer.

Source

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

	if s.config.Mode == configuration.CAT_MODE {
		seekInfo.Whence = io.SeekStart
	}

	if seekEnd {
		seekInfo.Whence = io.SeekEnd
	}

	logger.Infof("Starting tail (offset: %d, whence: %d)", seekInfo.Offset, seekInfo.Whence)

	tail, err := tail.TailFile(file, tail.Config{
		ReOpen:   true,
		Follow:   true,
		Poll:     pollFile,
		Location: seekInfo,
		Logger:   log.NewEntry(log.StandardLogger()),
	})
	if err != nil {
		return fmt.Errorf("could not start tailing file %s : %w", file, err)
	}

	s.tailMapMutex.Lock()
	s.tails[file] = true
	s.tailMapMutex.Unlock()

	t.Go(func() error {
		defer trace.ReportPanic()
		return s.tailFile(out, t, tail)
	})

	return nil
}

func (s *Source) tailFile(out chan pipeline.Event, t *tomb.Tomb, tail *tail.Tail) error {
	logger := s.logger.WithField("tail", tail.Filename)
	logger.Debug("-> start tailing")

View on GitHub (pinned to 909b515798)

Solutions

  1. Read the wrapped tail error in the log for the concrete cause (often 'file not found').
  2. Ensure the file exists and is readable at tail setup time.
  3. If logs rotate aggressively, enable poll_without_inotify / poll mode so rotation is handled gracefully.
  4. Check ulimit -n for the crowdsec process; each tailed file holds a descriptor.

Example fix

// acquis.yaml before
source: file
filenames:
  - /var/log/app.log
// after (tolerate rotation)
source: file
filenames:
  - /var/log/app.log
poll_without_inotify: true
Defensive patterns

Strategy: try-catch

Validate before calling

function canTail(path) {
  return fs.existsSync(path) && fs.statSync(path).isFile();
}

Try / catch

// retry tail init on transient races
for i := 0; i < 3; i++ {
    if err := setupTailForFile(...); err == nil { break }
    time.Sleep(time.Second)
}

Prevention

When it happens

Trigger: tail.TailFile(file, tail.Config{Follow:true, Poll:pollFile, Location:seekInfo, ...}) returns an error in setupTailForFile, called by StreamingAcquisition/checkAndTailFile.

Common situations: File deleted between validation and tail init; seek offset (Location) beyond file size after rotation/truncation with incompatible tail mode; permissions revoked; too many open files for the tailer.

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