{"record":{"id":"02dfee8cd3099bea","repo":"gastownhall/beads","slug":"metrics-file-emitter-w","errorCode":null,"errorMessage":"metrics: file emitter: %w","messagePattern":"metrics: file emitter: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/metrics/metrics.go","lineNumber":71,"sourceCode":"\tendpoint = metricsEndpoint\n\tif endpoint == \"\" {\n\t\tendpoint = DefaultEndpoint\n\t}\n\n\tvar emitter eventkit.Emitter = eventkit.NullEmitter{}\n\t// The distinct ID is resolved only on the enabled path: computing it can\n\t// fork a platform probe (see cachedMachineID), and a disabled collector\n\t// never emits an event that would carry it. The placeholder below is inert\n\t// — NullEmitter drops everything and WithDisabled gates emission anyway.\n\tdistinctID := \"disabled\"\n\tif enabled {\n\t\tdir, err := DataDir()\n\t\tif err != nil {\n\t\t\treturn func(context.Context) {}, fmt.Errorf(\"metrics: resolve data dir: %w\", err)\n\t\t}\n\t\tfe, err := eventkit.NewFileEmitter(dir)\n\t\tif err != nil {\n\t\t\treturn func(context.Context) {}, fmt.Errorf(\"metrics: file emitter: %w\", err)\n\t\t}\n\t\temitter = fe\n\t\tdistinctID = cachedMachineID(AppName)\n\t}\n\n\tc := eventkit.NewCollector(emitter,\n\t\teventkit.WithDistinctID(distinctID),\n\t\teventkit.WithAppName(AppName),\n\t\teventkit.WithAppVersion(version),\n\t\teventkit.WithDisabled(func() bool { return !enabled }),\n\t)\n\teventkit.SetGlobal(c)\n\n\treturn func(ctx context.Context) {\n\t\t_ = c.Close(ctx)\n\t}, nil\n}\n","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/metrics/metrics.go#L53-L89","documentation":"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.","triggerScenarios":"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.","commonSituations":"Read-only filesystem or full disk in the data dir; another process holding conflicting permissions; data dir deleted between DataDir() resolution and emitter creation.","solutions":["Check the wrapped cause (%w) and fix filesystem permissions/ownership on the data dir.","Free disk space or remove a file that collides with the emitter's path.","Disable metrics if telemetry is not needed in this environment (enabled=false or WithDisabled)."],"exampleFix":"// before\ncleanup, err := metrics.Init(ctx, true)\n// after\nif err := os.MkdirAll(dataDir, 0o755); err != nil {\n    return fmt.Errorf(\"data dir unusable: %w\", err)\n}\ncleanup, err := metrics.Init(ctx, true)","handlingStrategy":"fallback","validationCode":"if st, err := os.Stat(dataDir); err != nil || !st.IsDir() {\n    os.MkdirAll(dataDir, 0o755)\n}","typeGuard":null,"tryCatchPattern":"cleanup, err := metrics.Init(ctx, enabled)\nif err != nil && strings.HasPrefix(err.Error(), \"metrics: file emitter\") {\n    return nil // run without metrics rather than failing the command\n}","preventionTips":["Verify the data dir is writable before enabling metrics.","Monitor disk space in data-dir volumes.","Disable metrics on read-only filesystems."],"tags":["metrics","filesystem","emitter","io"],"backgroundTag":"file-emitter-init-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}