diff --git a/cmd/bd/daemon.go b/cmd/bd/daemon.go index cb6baaa0..13ea819b 100644 --- a/cmd/bd/daemon.go +++ b/cmd/bd/daemon.go @@ -452,6 +452,12 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush, autoPull, local } else if err := validateDatabaseFingerprint(ctx, store, &log); err != nil { if os.Getenv("BEADS_IGNORE_REPO_MISMATCH") != "1" { log.Error("repository fingerprint validation failed", "error", err) + // Write error to daemon-error file so user sees it instead of just "daemon took too long" + errFile := filepath.Join(beadsDir, "daemon-error") + // nolint:gosec // G306: Error file needs to be readable for debugging + if writeErr := os.WriteFile(errFile, []byte(err.Error()), 0644); writeErr != nil { + log.Warn("could not write daemon-error file", "error", writeErr) + } return // Use return instead of os.Exit to allow defers to run } log.Warn("repository mismatch ignored (BEADS_IGNORE_REPO_MISMATCH=1)") diff --git a/cmd/bd/daemon_autostart.go b/cmd/bd/daemon_autostart.go index 97419154..c4afc0d4 100644 --- a/cmd/bd/daemon_autostart.go +++ b/cmd/bd/daemon_autostart.go @@ -340,6 +340,17 @@ func startDaemonProcess(socketPath string) bool { recordDaemonStartFailure() debugLog("daemon socket not ready after 5 seconds") + + // Check for daemon-error file which contains the actual failure reason + beadsDir := filepath.Dir(dbPath) + errFile := filepath.Join(beadsDir, "daemon-error") + if errContent, err := os.ReadFile(errFile); err == nil && len(errContent) > 0 { + // Show the actual error from the daemon + fmt.Fprintf(os.Stderr, "%s Daemon failed to start:\n", ui.RenderWarn("Warning:")) + fmt.Fprintf(os.Stderr, "%s\n", string(errContent)) + return false + } + // Emit visible warning so user understands why command was slow fmt.Fprintf(os.Stderr, "%s Daemon took too long to start (>5s). Running in direct mode.\n", ui.RenderWarn("Warning:")) fmt.Fprintf(os.Stderr, " %s Run 'bd doctor' to diagnose daemon issues\n", ui.RenderMuted("Hint:")) diff --git a/cmd/bd/doctor/integrity.go b/cmd/bd/doctor/integrity.go index 07cf4bc8..646cd93e 100644 --- a/cmd/bd/doctor/integrity.go +++ b/cmd/bd/doctor/integrity.go @@ -441,12 +441,12 @@ func CheckRepoFingerprint(path string) DoctorCheck { err = db.QueryRow("SELECT value FROM metadata WHERE key = 'repo_id'").Scan(&storedRepoID) if err != nil { if err == sql.ErrNoRows || strings.Contains(err.Error(), "no such table") { - // Legacy database without repo_id + // Legacy database without repo_id - this is an error because daemon won't start return DoctorCheck{ Name: "Repo Fingerprint", - Status: StatusWarning, + Status: StatusError, Message: "Legacy database (no fingerprint)", - Detail: "Database was created before version 0.17.5", + Detail: "Database was created before version 0.17.5. Daemon will fail to start.", Fix: "Run 'bd migrate --update-repo-id' to add fingerprint", } } @@ -458,13 +458,13 @@ func CheckRepoFingerprint(path string) DoctorCheck { } } - // If repo_id is empty, treat as legacy + // If repo_id is empty, treat as legacy - this is an error because daemon won't start if storedRepoID == "" { return DoctorCheck{ Name: "Repo Fingerprint", - Status: StatusWarning, + Status: StatusError, Message: "Legacy database (empty fingerprint)", - Detail: "Database was created before version 0.17.5", + Detail: "Database was created before version 0.17.5. Daemon will fail to start.", Fix: "Run 'bd migrate --update-repo-id' to add fingerprint", } }