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:
co-authored by
Claude Fable 5
parent
21ee543012
commit
1d4f5dbce2
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user