Repository navigation
fix(http): raise TurnkeyActivityError when an activity does not complete - #21
Merged
Merged
Conversation
This was referenced Oct 16, 2026
Open
figitaki
force-pushed
the
carey/activity-errors
branch
from
October 17, 2026 23:31
6693a41 to
62bdc26
Compare
emostov
previously approved these changes
Oct 18, 2026
figitaki
marked this pull request as ready for review
October 18, 2026 00:08
figitaki
dismissed
emostov’s stale review
October 18, 2026 00:09
The merge-base changed after approval.
…sNeededError Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…mplete The emitted _activity helper returned response_type(activity=activity) for any status other than COMPLETED. Response models declare result fields as required, so callers got a pydantic ValidationError and lost the activity id and failure reason. The generic send_signed_request path matched result keys that end in "Result", so versioned keys such as createSubOrganizationResultV7 were skipped. It now takes the result field that is set. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
send_signed_request now raises TurnkeyActivityError only when a response_type is passed. Without one, it returns the raw payload for every status, as before, so callers can inspect a failed, rejected, or consensus-needed activity. Completed results still unpack, including versioned keys. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
figitaki
force-pushed
the
carey/activity-errors
branch
from
October 18, 2026 00:09
62bdc26 to
a7d36af
Compare
emostov
approved these changes
Oct 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.
Summary
Typed activity methods now raise a typed error when an activity does not complete. Before this change, they raised a pydantic
ValidationError.Stacks on #20. Merge #20 first.
Problem
_activitypolls the activity. If the status is notACTIVITY_STATUS_COMPLETED, it returnsresponse_type(activity=activity). The response models declare result fields as required, so pydantic rejects the response.Reproduction: call
client.create_wallet(...)with a policy that denies the activity. The call raisesValidationError: walletId Field required. The activity id and the failure reason are lost.Callers cannot tell a policy denial from a bug. Also, pydantic's
ValidationErroris a subclass ofValueError, so a broadexcept ValueErrorhid the problem.New behavior
New errors in
turnkey_sdk_types:TurnkeyActivityError(TurnkeyError)withactivity_id,activity_status,activity_type, andfailure(the failure message from Turnkey, if any). The names matchTurnkeyActivityErrorin@turnkey/http.TurnkeyActivityConsensusNeededError(TurnkeyActivityError).TurnkeyErrorCodes:ACTIVITY_FAILED,ACTIVITY_CONSENSUS_NEEDED,ACTIVITY_RESULT_MISSING.COMPLETEDwith the expected resultCOMPLETEDwithout the expected result keyTurnkeyActivityError(codeACTIVITY_RESULT_MISSING). The message names the expected keyCONSENSUS_NEEDEDTurnkeyActivityConsensusNeededErrorFAILEDTurnkeyActivityErrorwith the failure messageREJECTEDTurnkeyActivityErrorCREATED,PENDING,AUTHENTICATORS_NEEDED)TurnkeyActivityErrorwith the last status seen and the activity idsend_signed_requestwithoutresponse_typesend_signed_requestwith anACTIVITYrequest and aresponse_typeuses the same status check. Without aresponse_type,send_signed_requestdoes not raise. It returns the raw payload for every status, as before, so callers can inspect aFAILED,REJECTED, orCONSENSUS_NEEDEDactivity. When the activity completes, the raw payload also has the result fields._activity_decisiondoes not change. Its response types have onlyactivity, and aREJECTEDstatus is the expected result of a reject call.Generic path fix
send_signed_requestlooked for result attributes whose names end inResult. Versioned keys such ascreateSubOrganizationResultV7were skipped. Now it takes the first result field that is set on the activity result model. Pinned and latest result keys both work.Breaking change
Callers of typed activity methods that caught
ValidationError(orValueError) for non-completed activities now getTurnkeyActivityError. The same applies tosend_signed_requestwith aresponse_type. The raw path (send_signed_requestwithout aresponse_type) is unchanged. It still returns the activity for every status.Changes
codegen/http/generate_http.py, thenmake generate. The regenerated diff changes only_raise_for_activity_status(new),_activity, andsend_signed_request. No endpoint method bodies change.patchchangeset forhttpandsdk-types.Testing
packages/http/tests/test_activity_errors.py. They mockrequests.postand use a stub stamper. They need no credentials and do not use theconftest.pyfixtures. They cover a completed activity,FAILED,REJECTED,CONSENSUS_NEEDED, a polling timeout, a completed activity with a missing result key, acreateSubOrganizationResultV7result throughsend_signed_requestwith and without aresponse_type, a failed activity throughsend_signed_requestwith aresponse_type, and the raw path withFAILEDandCONSENSUS_NEEDED(no error, status and failure intact).v1Result.make typecheckpasses.ruff format --check .passes.test_activities.pyandtest_queries.pywere not run.🤖 Generated with Claude Code