gastownhall/beads · error

metrics: file emitter: %w

Error message

metrics: file emitter: %w

What it means

metrics.Init creates an eventkit.NewFileEmitter in the resolved data dir to persist metric events to disk. If the emitter cannot be constructed — directory unwritable at open time, path issues, or eventkit internal failure — Init returns 'metrics: file emitter: ...' with the underlying cause wrapped.

Source

Thrown at internal/metrics/metrics.go:71

	endpoint = metricsEndpoint
	if endpoint == "" {
		endpoint = DefaultEndpoint
	}

	var emitter eventkit.Emitter = eventkit.NullEmitter{}
	// The distinct ID is resolved only on the enabled path: computing it can
	// fork a platform probe (see cachedMachineID), and a disabled collector
	// never emits an event that would carry it. The placeholder below is inert
	// — NullEmitter drops everything and WithDisabled gates emission anyway.
	distinctID := "disabled"
	if enabled {
		dir, err := DataDir()
		if err != nil {
			return func(context.Context) {}, fmt.Errorf("metrics: resolve data dir: %w", err)
		}
		fe, err := eventkit.NewFileEmitter(dir)
		if err != nil {
			return func(context.Context) {}, fmt.Errorf("metrics: file emitter: %w", err)
		}
		emitter = fe
		distinctID = cachedMachineID(AppName)
	}

	c := eventkit.NewCollector(emitter,
		eventkit.WithDistinctID(distinctID),
		eventkit.WithAppName(AppName),
		eventkit.WithAppVersion(version),
		eventkit.WithDisabled(func() bool { return !enabled }),
	)
	eventkit.SetGlobal(c)

	return func(ctx context.Context) {
		_ = c.Close(ctx)
	}, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped cause (%w) and fix filesystem permissions/ownership on the data dir.
  2. Free disk space or remove a file that collides with the emitter's path.
  3. Disable metrics if telemetry is not needed in this environment (enabled=false or WithDisabled).

Example fix

// before
cleanup, err := metrics.Init(ctx, true)
// after
if err := os.MkdirAll(dataDir, 0o755); err != nil {
    return fmt.Errorf("data dir unusable: %w", err)
}
cleanup, err := metrics.Init(ctx, true)
Defensive patterns

Strategy: fallback

Validate before calling

if st, err := os.Stat(dataDir); err != nil || !st.IsDir() {
    os.MkdirAll(dataDir, 0o755)
}

Try / catch

cleanup, err := metrics.Init(ctx, enabled)
if err != nil && strings.HasPrefix(err.Error(), "metrics: file emitter") {
    return nil // run without metrics rather than failing the command
}

Prevention

When it happens

Trigger: eventkit.NewFileEmitter(dir) returning an error inside Init when metrics are enabled: data dir exists but is not writable, path is a file not a directory, or eventkit fails to open its event file.

Common situations: Read-only filesystem or full disk in the data dir; another process holding conflicting permissions; data dir deleted between DataDir() resolution and emitter creation.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/02dfee8cd3099bea. Report an issue: GitHub.