Fix JSON parsing crash on non-JSON API error responses#18
Merged
Conversation
…d ResponseContent properties Co-authored-by: fostimus <8053880+fostimus@users.noreply.github.com>
…prehensive tests Co-authored-by: fostimus <8053880+fostimus@users.noreply.github.com>
…n-JSON API responses Co-authored-by: fostimus <8053880+fostimus@users.noreply.github.com>
Co-authored-by: fostimus <8053880+fostimus@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix client crash on API error responses
Fix JSON parsing crash on non-JSON API error responses
Feb 21, 2026
Sets up .NET 10 SDK, restores dependencies, builds the solution, and runs the xUnit test suite on every pull request targeting master. https://claude.ai/code/session_01CjEQxmHFQCfseR6P6vWXLe
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add GitHub Actions CI workflow to run tests on PRs to master
fostimus
approved these changes
Mar 3, 2026
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.
dotnet-anvil Error Handling Changes
The Problem
When the Anvil API returned a non-JSON error response — most commonly a 429 rate limit with a plain-text body — the client crashed with a
JsonReaderExceptioninstead of surfacing the actual API error. Both the REST and GraphQL clients calledJsonConvert.DeserializeObjecton the response body without checking whether it was JSON first. This meant consumers couldn't catch or handle rate limits, gateway errors, or any other response that wasn't well-formed JSON.What Changed
All API errors — REST and GraphQL — now throw
AnvilClientExceptionwith structured error metadata. Non-JSON responses are handled gracefully: the raw response body, HTTP status code, and response headers are all available on the exception. Consumers no longer need to worry about the client crashing before they can inspect the error.0.6.0
Breaking Changes
GraphQL errors now throw
AnvilClientExceptionPreviously, HTTP-level errors from the GraphQL client threw
GraphQLHttpRequestException. They now throwAnvilClientExceptionwith the original preserved asInnerException.Before:
After:
SendGetRequestnow throws on error responsesPreviously,
SendGetRequestsilently returned failedHttpResponseMessageobjects without throwing. It now throwsAnvilClientException, consistent withSendPostRequest. This affectsDownloadDocumentsand any direct calls toSendGetRequest.Before:
After:
GraphQL error message format changed
Multiple GraphQL errors are now joined with
"; "instead of concatenated directly.Before:
"Field required""Email invalid"After:
"Field required; Email invalid"Individual messages are also available via
ex.Data["Message1"],ex.Data["Message2"], etc.Target framework simplified
The library now targets
netstandard2.0only, replacingnet5.0;netstandard2.0;net461. Sincenetstandard2.0is compatible with .NET Framework 4.6.1+, .NET Core 2+, and all modern .NET versions, most consumers are unaffected. Consumers that pinned tonet5.0ornet461should verify compatibility.New Features
AnvilClientExceptionpropertiesAll error paths now populate these properties:
HttpStatusCodeHttpStatusCode?ResponseHeadersDictionary<string, IEnumerable<string>>?ResponseContentstring?InnerExceptionException?Data["Message1"], etc.object?IDisposablesupportRestClientandGraphQLClientnow implementIDisposableto clean up their underlyingHttpClient. Existing code that doesn't callDispose()will continue to work.Bug Fixes
JsonExceptionand fall back gracefully, preserving the raw response content on the exception.RestClient.CreateExceptionFromResponseis now async. The previous implementation used.Resultto block onReadAsStringAsync(), which could deadlock in synchronous contexts or UI threads.EtchSigner.SignerTypeno longer throwsNullReferenceExceptionon null input.DocumentMarkup.MarkupandHtmlCssMarkup.Htmlnullable annotations fixed. These properties were annotated as non-nullable but could be null after JSON deserialization.messagefields are now skipped. Previously, JSON error entries without amessagekey would insertnullvalues into the exception'sDatadictionary.Dependencies
Newtonsoft.Jsonfrom 12.0.3 to 13.0.3 to resolve a high-severity vulnerability (GHSA-5crp-9r3c-p9vr).Internal
net10.0.InternalsVisibleToadded to support unit testing of internal error-wrapping logic.WrapGraphQLExceptionextracted as aninternal staticmethod fromSendQuery<T>to make GraphQL error-wrapping logic unit-testable without mocking HTTP calls.ResponseHeadersdictionaries useStringComparer.OrdinalIgnoreCasein both REST and GraphQL paths, since HTTP headers are case-insensitive.