Skip to content

Make resource operation outcomes explicit - #44

Merged
djgrant merged 6 commits into
mainfrom
resource-operation-outcomes
Jul 27, 2026
Merged

Make resource operation outcomes explicit#44
djgrant merged 6 commits into
mainfrom
resource-operation-outcomes

Conversation

@djgrant

@djgrantdjgrant commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

This PR removes the error-name and error-message matchers from resources.

Resource error API

Import both errors from @notation/resource:

import{ResourceNotFoundError,ResourceOperationPendingError,}from"@notation/resource";
newResourceNotFoundError(message: string,options?: {cause?: unknown });newResourceOperationPendingError(message: string,{retryAfterMs: number;callbackContext?: Readonly<Record<string,unknown>>;cause?: unknown;});
Handler resultMeaningReconciler action
Return normallyThe operation finished.Continue.
Throw ResourceNotFoundError from readNo resource exists for this key.Treat it as absent during planning and refresh.
Throw ResourceOperationPendingErrorThe operation has not finished.Wait, then call the same handler again.
Throw any other errorThe operation failed.Stop the deployment.

ResourceNotFoundError

thrownewResourceNotFoundError("Lambda function was not found",{cause: error,});

Only read throws this error. A delete handler must catch the provider's missing-resource error and return normally.

ResourceOperationPendingError

thrownewResourceOperationPendingError("Waiting for Lambda to become active",{retryAfterMs: 1_000,callbackContext: { requestId },cause: error,});

retryAfterMs is required. callbackContext is optional plain data. The reconciler passes it as the final argument on the next call:

read: async(key,callbackContext)=>{// ...};

The default limit is 30 calls. maxOperationAttempts changes the limit. A pending operation that reaches the limit fails.

The reconciler does not guess that a missing read after create or update is temporary. The resource must throw ResourceOperationPendingError if it knows the resource is still becoming visible.

Other changes

  • Removes ResourceNotReadyError, the matcher declarations, the old retry settings, and the indeterminate plan result.
  • Makes reading a missing zip side-effect free.
  • Stops plan input errors from being hidden as values that will become known later.
  • Keeps delete operations successful when the resource has already gone.

Tested with pnpm build, pnpm typecheck, and pnpm test:once.

A resource read now returns the remote object, or undefined when the
provider says it does not exist. Provider not-found exceptions are still
translated at the provider boundary; they just become undefined there.
Known temporary conditions - a Lambda that is still deploying, an IAM
role that has not propagated - throw ResourceNotReadyError, recognised
by its declared _tag rather than by class identity or message text. The
reconciler decides what that means: deploy, read and mutation workflows
retry it, while planning reports an indeterminate decision carrying the
message. Everything else propagates.
Drops the shared error-code matcher in favour of local checks at each
provider boundary.
@djgrant
djgrant marked this pull request as ready for review July 27, 2026 16:32
@djgrant
djgrant merged commit f7e9186 into mainJul 27, 2026
1 check failed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@djgrant