Implement "manufacturing an error never throws" doctrine#35
Merged
Conversation
Manufacturing an Error now never throws. Previously the same constructor mixed three policies for invalid input: silently default the code, throw on missing mandatory messages, and swallow a failing context configuration — the worst of both worlds (no fail-fast guarantee, yet silent defaults still hide real mistakes). - Missing (null/whitespace) diagnostic and short messages now fall back to a visible, documented sentinel (#MISSING_DIAGNOSTIC_MESSAGE / #MISSING_SHORT_MESSAGE) and the omission is recorded in the context under the #MISSING_REQUIRED_MESSAGE key, instead of throwing. - A configureContext delegate that throws now preserves the entries it added before failing, alongside #CANNOT_BUILD_ERROR_CONTEXT, rather than discarding the partial context. - Message normalization is centralized in the base Error constructor, removing the duplicated validation previously done in the Create factories and in WithPublicMessage. - Aligned the PrimaryPort/SecondaryPort inner-error Add docs with the actual behavior: a null error is ignored, not rejected (the docs previously said "Must not be null"). Null enumerable inner-error entries remain filtered out (unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URc4t7KDuwgbq1yU4E6y6t
78acb35 to
2a53b53
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactor error construction to follow a "manufacturing an error never throws" doctrine: invalid or missing inputs now degrade to documented, visible fallbacks instead of being rejected with exceptions. This makes error creation more resilient on failure paths (inside
catchblocks, during logging, etc.) where secondary exceptions would mask the original problem.Type of change
Changes
Error message validation: Changed from throwing
ArgumentNullException/ArgumentExceptionto coalescing missing or whitespace mandatory messages to sentinel values:nullor whitespaceDiagnosticMessage→Error.MissingDiagnosticMessage(#MISSING_DIAGNOSTIC_MESSAGE)nullor whitespaceShortMessage→Error.MissingShortMessage(#MISSING_SHORT_MESSAGE)Context recording: Missing mandatory messages are now recorded in the error context under the
#MISSING_REQUIRED_MESSAGEkey (newErrorContextKey.MissingRequiredMessages) as anIReadOnlyList<string>of parameter names, making the omission diagnosable.Context configuration resilience: When a
configureContextdelegate throws, the exception is captured under the#CANNOT_BUILD_ERROR_CONTEXTkey, and context entries added before the failure are preserved instead of being discarded.Null inner errors: Silently dropped instead of rejected (consistent with the doctrine).
Test updates:
ANullDiagnosticMessageIsRejected,AnEmptyOrWhitespaceDiagnosticMessageIsRejected,ANullShortMessageIsRejected,AnEmptyOrWhitespaceShortMessageIsRejected) to verify fallback behavior and context recording.[Collection("SmartEnumSideEffects")]andIDisposabletoErrorDefensiveTestsfor proper test isolation.API simplification: Removed early validation in
DomainError.Create(),InfrastructureError.Create(),PrimaryPortError.Create(), andSecondaryPortError.Create()— all normalization now happens in the baseErrorconstructor.Documentation: Updated XML docs in
Error,PublicMessageStage,PrimaryPortInnerErrors,SecondaryPortInnerErrors, andErrorContextKeyto reflect the new doctrine and behavior.Testing
dotnet build FirstClassErrors.slndotnet test FirstClassErrors.slnAll existing tests pass; new tests verify the fallback behavior and context recording.
Documentation
Updated XML documentation in
Error.cs,PublicMessageStage.cs,ErrorContextKey.cs, and related classes to document the "manufacturing an error never throws" doctrine and the new sentinel values and context keys.https://claude.ai/code/session_01URc4t7KDuwgbq1yU4E6y6t