Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e3af35b54 | |||
| a631c8c3c3 |
+1
-12
@@ -341,18 +341,7 @@ export const addTransactionCapability = (
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// SessionError is part of the normal Bad MAC recovery flow
|
logger.error({ error }, 'transaction failed, rolling back')
|
||||||
// (retry receipt → sender resends as pkmsg → new session within ~1.3s).
|
|
||||||
// Logging it as ERROR creates 2 noise lines per recoverable Bad MAC cycle.
|
|
||||||
// Downgrade to debug for SessionError; keep ERROR for everything else.
|
|
||||||
// The error is still re-thrown — recovery behavior is unchanged.
|
|
||||||
const errName = (error as { name?: string })?.name
|
|
||||||
if (errName === 'SessionError') {
|
|
||||||
logger.debug({ error }, 'transaction failed (SessionError — recoverable via retry receipt)')
|
|
||||||
} else {
|
|
||||||
logger.error({ error }, 'transaction failed, rolling back')
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -58,11 +58,7 @@ export const BAD_MAC_ERROR_TEXT = 'Bad MAC'
|
|||||||
export const DECRYPTION_RETRY_CONFIG = {
|
export const DECRYPTION_RETRY_CONFIG = {
|
||||||
maxRetries: 3,
|
maxRetries: 3,
|
||||||
baseDelayMs: 100,
|
baseDelayMs: 100,
|
||||||
// 'No matching sessions found' is the libsignal error when decryptWithSessions exhausts
|
sessionRecordErrors: ['No session record', 'SessionError: No session record'],
|
||||||
// all stored sessions for a JID. Same recovery flow (retry receipt → pkmsg → new session)
|
|
||||||
// — categorise it as session-record so the caller logs DEBUG on retry, ERROR only when
|
|
||||||
// retries are exhausted (instead of dumping the full stack as an unknown error).
|
|
||||||
sessionRecordErrors: ['No session record', 'SessionError: No session record', 'No matching sessions found'],
|
|
||||||
corruptedSessionErrors: ['Bad MAC', 'MessageCounterError', MISSING_KEYS_ERROR_TEXT]
|
corruptedSessionErrors: ['Bad MAC', 'MessageCounterError', MISSING_KEYS_ERROR_TEXT]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,26 +421,9 @@ export const decryptMessageNode = (
|
|||||||
const isCorrupted = isCorruptedSessionError(originalError)
|
const isCorrupted = isCorruptedSessionError(originalError)
|
||||||
const isSessionRecord = isSessionRecordError(originalError)
|
const isSessionRecord = isSessionRecordError(originalError)
|
||||||
|
|
||||||
// Slim error projection — keep name/message/type for diagnosis,
|
|
||||||
// drop `stack` which adds 4-5 lines of node_modules paths per log
|
|
||||||
// for known-recoverable libsignal errors.
|
|
||||||
//
|
|
||||||
// CRITICAL: only slim for KNOWN-RECOVERABLE categories (corrupted /
|
|
||||||
// session-record). The unknown-error branch keeps the full Error so
|
|
||||||
// protobuf/parsing/runtime bugs still emit a stack trace where it
|
|
||||||
// matters most. Catches Copilot/Codex P2 review on PR #391.
|
|
||||||
const slimErr = originalError
|
|
||||||
? {
|
|
||||||
name: (originalError as { name?: string }).name,
|
|
||||||
message: (originalError as { message?: string }).message,
|
|
||||||
type: (originalError as { type?: string }).type
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
const isRecoverableCategory = isCorrupted || isSessionRecord
|
|
||||||
|
|
||||||
const errorContext = {
|
const errorContext = {
|
||||||
key: fullMessage.key,
|
key: fullMessage.key,
|
||||||
err: isRecoverableCategory ? slimErr : originalError,
|
err: originalError,
|
||||||
messageType: tag === 'plaintext' ? 'plaintext' : attrs.type,
|
messageType: tag === 'plaintext' ? 'plaintext' : attrs.type,
|
||||||
sender,
|
sender,
|
||||||
author,
|
author,
|
||||||
|
|||||||
+2
-11
@@ -28,16 +28,7 @@ console.info = function (...args: unknown[]) {
|
|||||||
|
|
||||||
// Track errors by type + JID to avoid duplicates (using Map for better performance)
|
// Track errors by type + JID to avoid duplicates (using Map for better performance)
|
||||||
const _errorTimestamps = new Map<string, number>()
|
const _errorTimestamps = new Map<string, number>()
|
||||||
// Dedup window for repeated decrypt-error console lines (Bad MAC / Counter / etc).
|
const DEDUP_WINDOW_MS = 150
|
||||||
// Was 150ms, but retry attempts of the SAME message are typically ~300-1000ms apart,
|
|
||||||
// so the second attempt fell outside the window and double-printed.
|
|
||||||
//
|
|
||||||
// TRADE-OFF: dedup key is `errorType + JID` (no message-id). With 5s, a burst of
|
|
||||||
// errors for the SAME JID — even of slightly different categories or different
|
|
||||||
// messages — collapses to one log line every 5s. This is intentional for a noisy
|
|
||||||
// production stream; if you need per-message visibility, set BAILEYS_LOG_LEVEL=debug
|
|
||||||
// to bypass this console-side dedup and see the structured pino logs in full.
|
|
||||||
const DEDUP_WINDOW_MS = 5000
|
|
||||||
|
|
||||||
console.error = function (...args: unknown[]) {
|
console.error = function (...args: unknown[]) {
|
||||||
if (args.length > 0 && typeof args[0] === 'string') {
|
if (args.length > 0 && typeof args[0] === 'string') {
|
||||||
@@ -79,7 +70,7 @@ console.error = function (...args: unknown[]) {
|
|||||||
const lastTime = _errorTimestamps.get(dedupeKey)
|
const lastTime = _errorTimestamps.get(dedupeKey)
|
||||||
|
|
||||||
if (lastTime && now - lastTime < DEDUP_WINDOW_MS) {
|
if (lastTime && now - lastTime < DEDUP_WINDOW_MS) {
|
||||||
return // Skip duplicate within DEDUP_WINDOW_MS window
|
return // Skip duplicate within 150ms window
|
||||||
}
|
}
|
||||||
|
|
||||||
_errorTimestamps.set(dedupeKey, now)
|
_errorTimestamps.set(dedupeKey, now)
|
||||||
|
|||||||
Reference in New Issue
Block a user