fix(diagnostics): bind empty playback_session_ids and log ingest failures

pgx binds a nil Go slice as SQL NULL, which bypasses the column's '{}'
default and violates its NOT NULL constraint, so reports without
playback session ids failed to insert. Bind an empty slice instead.

The ingest path also swallowed the underlying insert and bundle
validation errors, logging only a generic rejection reason; both sites
now log the real error so failures are diagnosable from server logs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012e3QjbPo96ed9Mn2qRiUkh
This commit is contained in:
Quick104
2026-07-21 08:17:03 -04:00
co-authored by Claude Fable 5
parent 21ee543012
commit 1d4f5dbce2
2 changed files with 19 additions and 1 deletions
+7 -1
View File
@@ -69,6 +69,12 @@ func (r *PostgresRepository) InsertReceiving(ctx context.Context, input InsertRe
}
crashSummary := truncateCrashSummary(input.CrashSummary)
sessionIDs := input.PlaybackSessionIDs
if sessionIDs == nil {
// pgx binds a nil slice as SQL NULL, which bypasses the column's
// '{}' default and violates its NOT NULL constraint.
sessionIDs = []string{}
}
for attempt := 0; attempt < retries; attempt++ {
id := reportIDGenerator()
if _, err := uuid.Parse(id); err != nil {
@@ -95,7 +101,7 @@ func (r *PostgresRepository) InsertReceiving(ctx context.Context, input InsertRe
`, id, shortID, input.UserID, nullableString(input.ProfileID), input.CapturedAt,
strings.TrimSpace(input.ReportType), strings.TrimSpace(input.Platform),
strings.TrimSpace(input.AppVersion), nullableString(crashSummary),
string(input.Manifest), input.PlaybackSessionIDs).Scan(&insertedID, &insertedShortID)
string(input.Manifest), sessionIDs).Scan(&insertedID, &insertedShortID)
if errors.Is(err, pgx.ErrNoRows) {
continue
}
+12
View File
@@ -172,6 +172,12 @@ func (s *Service) Ingest(ctx context.Context, userID int, profileID *string, man
reason := "insert_failed"
if errors.Is(err, ErrQuotaExceeded) {
reason = "quota_exceeded"
} else {
s.logger.ErrorContext(ctx, "diagnostic report insert failed",
"component", "diagnostics",
"user_id", userID,
"error", err,
)
}
s.logRejected(ctx, "", userID, manifest.Report.Platform, manifest.Report.Type, manifest.Archive.Bytes, reason)
return IngestResult{}, err
@@ -182,6 +188,12 @@ func (s *Service) Ingest(ctx context.Context, userID int, profileID *string, man
if err != nil {
s.compensateFailedUpload(ctx, reserved.ID, key)
rejectErr := classifyBundleUploadError(err)
s.logger.ErrorContext(ctx, "diagnostic bundle validation failed",
"component", "diagnostics",
"report_id", reserved.ID,
"user_id", userID,
"error", err,
)
s.logRejected(ctx, reserved.ID, userID, manifest.Report.Platform, manifest.Report.Type, manifest.Archive.Bytes, rejectReason(rejectErr))
return IngestResult{}, rejectErr
}