redactErrorForReporting static method
Redacts an error before it is forwarded to a reporter from the error
chokepoint (_recordErrorSafe, Phase 3). Reuses the central, backend-
agnostic redaction (ERH-005) so error payloads get the same fail-closed
scrubbing as breadcrumbs (BEH-8).
Applies the v1 pattern set to error.toString(). When the redacted string
differs from the original (a secret was scrubbed), the redacted STRING
is returned so the secret never reaches the backend. When it is unchanged
the original error object is returned untouched — so reporters keep the
rich error type (and the stack, which the caller forwards separately) in the
common no-secret case.
Fail-closed (ERH-017, ERH-047 / BEH-8): on ANY redaction error the
error is replaced with a placeholder derived from the redaction error's
runtimeType (e.g. [redaction-error: NotAllowedError]) — never
toString(), which could embed a secret — with a console-only diagnostic;
nothing unredacted is ever forwarded. The stack is preserved by the caller
(it is not passed here). Never throws.
NOTE: dedup (Phase 3) keys on the ORIGINAL (error, stackTrace) identity
before this runs, so a fail-closed placeholder can never collapse two
distinct errors into one (ERH-028 / BEH-9).
Implementation
static Object redactErrorForReporting(Object error) {
try {
final original = error.toString();
final redacted = _redactString(original);
// Unchanged → keep the original object (rich type preserved). Changed →
// forward the redacted string so the secret is scrubbed.
return identical(redacted, original) || redacted == original ? error : redacted;
} catch (e) {
final placeholder = '[redaction-error: ${e.runtimeType}]';
if (kReleaseMode && kIsWeb) {
// ignore: avoid_print
print('Error redaction failed; replacing with placeholder ($placeholder).');
} else {
debugPrint('Error redaction failed; replacing with placeholder ($placeholder).');
}
return placeholder;
}
}