Use this file to discover all available pages before exploring further.
The Sprites Go SDK surfaces errors through the same patterns as the standard library’s os/exec package, with additions for API-level failures like rate limiting and authentication errors. Understanding which error type you receive tells you whether a problem originated in the remote process, the network, or the API itself.
When a command exits with a non-zero status code, Run, Wait, and Output return an *ExitError:
type ExitError struct { Code int}func (e *ExitError) Error() string // "exit status N"func (e *ExitError) ExitCode() int // returns Code
Use errors.As to unwrap it and read the exit code:
cmd := sprite.Command("false")err := cmd.Run()var exitErr *sprites.ExitErrorif errors.As(err, &exitErr) { fmt.Printf("process exited with code %d\n", exitErr.ExitCode())} else if err != nil { // Connection, auth, or other infrastructure error. log.Fatal(err)}
The SDK also accepts the direct type assertion form shown in the README — err.(*sprites.ExitError) — but errors.As is preferred because it correctly unwraps errors that have been wrapped with fmt.Errorf("%w", ...).
Distinguishing process errors from infrastructure errors
A concrete decision tree for the errors returned by Run / Wait:
err := cmd.Run()if err == nil { // Success, exit code 0. return}var exitErr *sprites.ExitErrorswitch {case errors.As(err, &exitErr): // The process ran and exited with a non-zero code. fmt.Println("exit code:", exitErr.ExitCode())case errors.Is(err, context.DeadlineExceeded): // The context timed out before the process finished. fmt.Println("command timed out")case errors.Is(err, context.Canceled): // The context was cancelled explicitly. fmt.Println("command cancelled")default: // Network, WebSocket, or authentication failure. fmt.Println("infrastructure error:", err)}
HTTP errors from the Sprites API are returned as *APIError:
type APIError struct { ErrorCode string // machine-readable code, e.g. "sprite_creation_rate_limited" Message string // human-readable message Limit int // rate limit value WindowSeconds int // rate limit window RetryAfterSeconds int // seconds to wait before retrying (from JSON body) CurrentCount int // current concurrent count UpgradeAvailable bool UpgradeURL string StatusCode int // HTTP status code RetryAfterHeader int // seconds from Retry-After header}
Use sprites.IsAPIError to check for and extract API errors:
ctx, cancel := context.WithCancel(context.Background())cmd := sprite.CommandContext(ctx, "watch", "-n1", "date")go func() { time.Sleep(5 * time.Second) cancel() // Stop the command after 5 seconds.}()err := cmd.Run()if errors.Is(err, context.Canceled) { fmt.Println("command was cancelled")}
Contexts are also respected by checkpoint and list operations:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)defer cancel()stream, err := sprite.CreateCheckpoint(ctx)// If the checkpoint takes longer than 10 seconds, ctx.Err() is returned.
When the WebSocket connection is dropped before the process exits, Wait returns "connection closed". This is distinct from an ExitError (process ran to completion with a non-zero code) and from a context error (explicit cancellation or deadline):
Every command execution can fail due to a non-zero exit code, a lost connection, or a context cancellation. Ignoring the returned error masks real failures.
// Bad: ignoring the error.cmd.Run()// Good: handling the error.if err := cmd.Run(); err != nil { var exitErr *sprites.ExitError if errors.As(err, &exitErr) { fmt.Println("exit code:", exitErr.ExitCode()) } else { log.Fatal(err) }}
Use errors.As, not direct type assertions
The SDK wraps some errors with fmt.Errorf("%w", ...). errors.As traverses the chain correctly; a bare type assertion does not.
// Fragile: fails if the error is wrapped.if exitErr, ok := err.(*sprites.ExitError); ok { ... }// Robust: works regardless of wrapping.var exitErr *sprites.ExitErrorif errors.As(err, &exitErr) { ... }
Set timeouts on long-running commands
Commands that talk to external services or perform heavy computation should always run under a context with a deadline. This prevents goroutine leaks when the sprite becomes unresponsive.
A Cmd cannot be reused. After Run or Wait returns, discard the value and create a new one with sprite.Command.
// Bad: reusing the same Cmd.cmd := sprite.Command("echo", "hello")cmd.Run()cmd.Run() // returns "sprite: already started"// Good: create a new Cmd each time.for i := 0; i < 3; i++ { if err := sprite.Command("echo", "hello").Run(); err != nil { log.Fatal(err) }}