Skip to content

Error Handling

All Turbine errors use the Error type with specific error codes.

Error

go
type Error struct {
    Message         string
    Code            ErrorCode
    WorkflowID      string
    DestinationID   string
    StepName        string
    QueueName       string
    DeduplicationID string
    MaxRetries      int
}

Error Codes

CodeMeaning
ErrConflictingIDA workflow with this ID already exists
ErrWorkflowNotFoundNo workflow found with the given ID
ErrWorkflowConflictConflicting workflow invocation with the same ID
ErrCancelledWorkflow was cancelled
ErrAwaitCancelledA workflow being awaited was cancelled
ErrRegistrationConflictWorkflow name or FQN already registered
ErrDeadLetterWorkflow exceeded max recovery attempts
ErrMaxRetriesStep exceeded max retry attempts
ErrDeduplicatedWorkflow was deduplicated (duplicate in queue)

Matching Errors

Use errors.Is to check for specific error codes:

go
handle, err := turbine.Run(rt, myWorkflow, input, turbine.WithID("order-123"))
if err != nil {
    var ptErr *turbine.Error
    if errors.As(err, &ptErr) {
        fmt.Println(ptErr.Code, ptErr.WorkflowID)
    }

    // Or match by code directly
    if errors.Is(err, &turbine.Error{Code: turbine.ErrConflictingID}) {
        // workflow with this ID already exists
    }
    if errors.Is(err, &turbine.Error{Code: turbine.ErrDeduplicated}) {
        // duplicate was suppressed
    }
}

Common Patterns

Idempotent Workflow Starts

Use WithID and handle ErrConflictingID to safely retry:

go
handle, err := turbine.Run(rt, processOrder, orderID,
    turbine.WithID("order-" + orderID),
)
if errors.Is(err, &turbine.Error{Code: turbine.ErrConflictingID}) {
    // already running — retrieve existing handle
    handle = turbine.Retrieve[string](rt, "order-" + orderID)
}

Handling Cancellation

go
result, err := handle.GetResult()
if errors.Is(err, &turbine.Error{Code: turbine.ErrCancelled}) {
    // workflow was cancelled
}

Step Retry Exhaustion

When a step exceeds its max retries, the error wraps the original cause:

go
result, err := turbine.Do(ctx, unreliableStep,
    turbine.WithStepMaxRetries(3),
)
if errors.Is(err, &turbine.Error{Code: turbine.ErrMaxRetries}) {
    // step failed after 3 retries
    // errors.Unwrap(err) returns the last step error
}

Sentinel Errors

In addition to Error, Turbine defines sentinel errors:

ErrorMeaning
turbine.ErrShuttingDownRuntime is shutting down, not accepting new workflows
turbine.ErrApprovalTimeoutWaitForApproval timed out (see Approvals)
go
if errors.Is(err, turbine.ErrShuttingDown) {
    // runtime is draining
}