fix(EXT-4): handle GraphQL error and partial-data responses explicitly - #160
Merged
Conversation
When the Linear API returns HTTP 200 with both "data" and "errors" (partial-success), the field-level errors were silently discarded. Now emits a Logger.warning so operators can see when data is incomplete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uses
- Add `else` clauses to `with` chains in all ManualRead read/3 modules
so unexpected shapes return `{:error, {:unexpected_response, ...}}`
instead of passing the raw value through (which Ash can't handle).
- Normalize `{:http_error, status, body}` 3-tuples to `{:http_error, status}`
2-tuples at the ManualRead boundary. Splode (Ash's error library) only
stores 2-tuples (keyword list elements) in `UnknownError.value`; 3-tuples
fall through to a string representation that prevents pattern matching in
handle_error/3.
- Fix `Map.fetch!` crash in Paginate.do_all when the expected connection
field is absent: replace with safe `fetch_connection/2` helper that
returns `{:error, {:unexpected_response, ...}}` instead of raising.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ures - HTTP 401/403: print targeted auth-failure message and exit 77 - Other HTTP errors: print the status code and exit 88 - Transport errors (DNS failure, ECONNREFUSED, timeout): print network message and exit 69 - Unexpected response shape (200 with neither data nor errors): exit 88 Previously all these fell through to the catch-all "What the heck is this?" handler, giving users no actionable information. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add retry: false to test config to prevent Req's exponential backoff from slowing transport-error tests. - Add tests for unexpected_response, http 401/403, http 500, and transport error paths in CLITest. - Add UserTest coverage for viewer=nil and absent-viewer-key responses. - Add IssueTest coverage for absent connection field in Paginate.all. - Fix "unexpected raise" test: nil["key"] returns nil in Elixir (Atom implements Access), so use a non-enumerable nodes value instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Credo --strict flags a with expression that has exactly one <- clause and an else branch as less readable than an equivalent case. Convert all eight affected ManualRead call sites in label, project, team, user, and workflow_state. Also reformat api.ex's partial-success clause to satisfy mix format --check-formatted. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bougyman
pushed a commit
that referenced
this pull request
Aug 20, 2026
🤖 I have created a release *beep* *boop* --- ## [1.16.0](v1.15.2...v1.16.0) (2026-08-20) ### Features * **EXT-5:** show workflow status in compact and full issue listings ([#162](#162)) ([acf35e5](acf35e5)) ### Bug Fixes * **EXT-4:** handle GraphQL error and partial-data responses explicitly ([#160](#160)) ([31359ef](31359ef)) * **EXT-7:** bundle musl NIF for Linux Burrito releases and container ([#163](#163)) ([3172d4e](3172d4e)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
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
"data"and"errors"):Api.call/2already returned{:ok, data}for these; now also emitsLogger.warningso field-level errors aren't silently discarded.elseclauses to everywithchain in ManualRead modules (team,user,label,workflow_state,project,paginate). Without them, unexpected API shapes returned as raw values that Ash couldn't handle.{:http_error, status, body}(3-tuple) is normalized to{:http_error, status}(2-tuple) at the ManualRead boundary. Splode only stores 2-tuples inUnknownError.value; 3-tuples fell into a string representation that blocked pattern matching.Map.fetch!with a safefetch_connection/2helper that returns{:error, {:unexpected_response, ...}}instead of raisingKeyError.handle_error/3clauses forhttp_error 401/403(exit 77),http_error other(exit 88),transport_error(exit 69), andunexpected_response(exit 88). All previously fell through to the generic catch-all with no actionable message.Test plan
mix test test/linear_cli/cli_test.exs— all 27 pass including new HTTP/transport/unexpected testsmix test— 293/307 pass; 14 failures are pre-existing GPG signing env failures unrelated to this changemix compile --warnings-as-errors— cleanuser_test.exs(viewer=nil, absent viewer key) andissue_test.exs(absent connection field in Paginate)Closes EXT-4
🤖 Generated with Claude Code