Stop the GL account-code check from being able to abort startup

The catch filter only matched DomainException/OperationCanceledException,
so anything else escaped a hosted service and took the host down. One such
path was mine: `"items": null` deserializes over the property initialiser,
so `data.Items.Select(...)` would NullReferenceException straight past the
filter.

Fixed at both ends - the reader tolerates a null or absent items array, and
the catch is now a deliberate catch-all that only lets a genuine host
shutdown through. This is a diagnostic; a diagnostic that can core-dump the
thing it diagnoses is worse than no diagnostic at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 11:53:31 +05:30
parent e0601d5a8d
commit 3c8837e21e
3 changed files with 33 additions and 7 deletions
@@ -1,5 +1,4 @@
using ERPCore.Services.Interfaces;
using ERPCore.System.Errors;
namespace ERPCore.Infra.Gl;
@@ -61,10 +60,12 @@ public sealed class GlAccountCodeValidator(
timeout.CancelAfter(FetchTimeout);
present = await gl.ListAccountCodesAsync(timeout.Token);
}
catch (Exception e) when (e is DomainException or OperationCanceledException && !ct.IsCancellationRequested)
// Catch-all on purpose. This is a diagnostic, and a diagnostic that can abort the host is
// worse than no diagnostic — whatever GL answers with (unreachable, a timeout, a redirect,
// an unparseable body, a shape this reader mishandles) must degrade to a log line, never a
// core-dump. The only exception that still propagates is a genuine host shutdown.
catch (Exception e) when (!ct.IsCancellationRequested)
{
// Unreachable, timed out, or rejected the read — can't verify, so don't block startup.
// The per-flow 404 remains the backstop it has always been.
logger.LogWarning(e,
"Could not read GL's chart of accounts at startup; {Count} configured account code(s) left unverified.",
expected.Length);