feat(sdk)!: the Java client reads the error contract it is answered with - #130
Merged
Merged
Conversation
Refusals were matched by substring over the raw body, and retries went by status alone. DatahubApiException.problem() now exposes the RFC 9457 document (Problem, new in api-model, never null) and ingest follows its retry member: a 409 optimistic-lock is retried, a 500 internal is not, and Retry-After is the backoff floor. Buffering stays status-based on purpose. A 401 is change-request, yet spooling it while a credential is renewed is what the spool is for. The binary stale-series retry reads type and reason instead of searching the whole body, which also fired on a detail sentence naming a series. Its test fixtures were still the pre-errors/9 shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
olavgg
approved these changes
Sep 18, 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.
The API converged on one RFC 9457 shape (
errors/1–15). The Java SDK had not caught up: it matched error types by substring over the raw body and classified retries by status code alone.What changed
Problem(new,datahub-api-model, Apache-2.0) — the wire contract read. Typedtype/title/status/detail/instance/retry/requestId/fields; everything else inextensions(), since RFC 9457 §3.2 requires unknown members to be tolerated.Problem.of(status, body)never throws and never returns null, so an error path needs no special case for a proxy's HTML or an empty 502 (slug()is simply null there). Mirrors the console'sDataHubProblem, which reads the same shape in the browser.DatahubApiException.problem()— never null. The message now carries title, detail, rejected fields andrequestIdinstead of justHTTP 409 for POST /x.ApiHttp— asks forapplication/problem+jsonas well asapplication/json, and carriesRetry-After.Classification — three substring matches are gone:
tenant-limit-reached,unknown-timeseries,external-id-mismatch. The last two also fired on adetailsentence merely naming a series.Behaviour changes worth review
retry. A409 optimistic-lockis now retried; a500 internal(needs-operator) is not. Correct per the contract, but note a momentary DB-pool exhaustion inside the API is also a500 internal. If that should be retryable the fix belongs inProblems.retryFor, not here.Retry-Afterover 30s fails the batch immediately rather than sleeping. A spent daily quota returns at midnight UTC, so the spool should hold it, not a parked thread.retry. A401ischange-request, yet spooling it while a credential is renewed is the whole point of the spool.isRetryableandisBufferableanswer different questions; bothAGENTS.mdand the javadoc say so.Also
TimeseriesBinaryIngestTestfixtures were still the pre-errors/9shape (type: datapoint-block-rejected), which is why matching ontypeturned them red. Updated to whatDatapointBlockRejectedExceptionsends today.BatchErrorgains a fifth component; the 3- and 4-arg constructors are kept, so it stays source-compatible.Tests
16 new (
ProblemTest,ProblemContractTest,IngestRetryContractTest, plus three wire-level cases inTimeseriesIngestTest). Full repo compiles;:datahub-java-sdk:testand:datahub-api-model:testgreen.Docs
datahub-sdk-docs: IntelliStream-DataHub/datahub-sdk-docs#95
Follow-up, not in this PR: the API's doc-only
ApiProblem/FieldProblemcould now point at api-model'sProblem, finishing what c0deda8 started.🤖 Generated with Claude Code