{"record":{"id":"cd4d2101e9725e59","repo":"bytebase/bytebase","slug":"failed-to-send-signal","errorCode":null,"errorMessage":"failed to send signal","messagePattern":"failed to send signal","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/store/signal.go","lineNumber":30,"sourceCode":"// SignalChannel is the PostgreSQL NOTIFY channel for HA coordination.\nconst SignalChannel = \"bytebase_signal\"\n\n// SendSignal sends a notification to the bytebase_signal channel.\nfunc (s *Store) SendSignal(ctx context.Context, signalType storepb.Signal_Type, projectID string, uid int64, approvalInputVersion *int64) error {\n\tsignal := &storepb.Signal{\n\t\tType:    signalType,\n\t\tUid:     uid,\n\t\tProject: projectID,\n\t}\n\tif approvalInputVersion != nil {\n\t\tsignal.ApprovalInputVersion = *approvalInputVersion\n\t}\n\tpayload, err := protojson.Marshal(signal)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"failed to marshal signal payload\")\n\t}\n\t_, err = s.GetDB().ExecContext(ctx, \"SELECT pg_notify($1, $2)\", SignalChannel, string(payload))\n\treturn errors.Wrap(err, \"failed to send signal\")\n}\n","sourceCodeStart":12,"sourceCodeEnd":32,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/store/signal.go#L12-L32","documentation":"SendSignal publishes a payload via pg_notify($1, $2) on the store's LISTEN/NOTIFY channel. This error wraps any failure of that ExecContext call — the payload was marshalled successfully but Postgres refused or could not execute the NOTIFY. Causes include a dead/broken DB connection, the notification payload exceeding NOTIFY's 8000-byte limit, or the session being in a failed transaction state.","triggerScenarios":"Calling CancelPlanCheckRun or BatchCancelTaskRuns when: the metadata DB connection is down or dropped; the protojson payload string exceeds Postgres NOTIFY's 8000-byte maximum; the context is cancelled/timed out before the query runs; or the call is made inside an aborted transaction.","commonSituations":"Network blips between the Bytebase server and Postgres; very large check-run payloads after schema growth; connection pool exhaustion returning stale connections; Postgres restarts during deploys.","solutions":["Check the wrapped error for context (connection reset, context deadline, or 'payload string too long').","Log the marshalled payload length before calling SendSignal and trim/split signals approaching the 8000-byte NOTIFY limit.","Verify metadata DB connectivity (PG_URL) and that the connection pool is healthy; retry transient failures with backoff.","Ensure SendSignal is not invoked from within an aborted transaction; run it on a fresh session/connection."],"exampleFix":"// before\n_, err = s.GetDB().ExecContext(ctx, \"SELECT pg_notify($1, $2)\", SignalChannel, string(payload))\n// after\npayloadStr := string(payload)\nif len(payloadStr) > 8000 {\n  return errors.Errorf(\"signal payload %d bytes exceeds pg_notify 8000-byte limit\", len(payloadStr))\n}\n_, err = s.GetDB().ExecContext(ctx, \"SELECT pg_notify($1, $2)\", SignalChannel, payloadStr)","handlingStrategy":"retry","validationCode":"payloadStr := string(marshalledPayload)\nif len(payloadStr) > 8000 {\n  return errors.Errorf(\"signal payload %d bytes exceeds pg_notify 8000-byte limit\", len(payloadStr))\n}\nif err := ctx.Err(); err != nil {\n  return err // context already cancelled\n}","typeGuard":null,"tryCatchPattern":"err := store.SendSignal(ctx, ws, signal)\nif err != nil && strings.Contains(err.Error(), \"failed to send signal\") {\n  // transient DB failure: retry with backoff\n  select {\n  case <-time.After(2 * time.Second):\n    err = store.SendSignal(ctx, ws, signal)\n  case <-ctx.Done():\n    return ctx.Err()\n  }\n}","preventionTips":["Keep signal payloads small; NOTIFY is capped at 8000 bytes.","Call SendSignal outside of transactions so an aborted tx cannot poison the notify.","Monitor metadata DB connectivity; alert on connection resets.","Never ignore the error — the cancel action silently won't reach listeners if dropped."],"tags":["database","postgres","notify","network"],"backgroundTag":"database-query-failed","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}