Skip to content

Latest commit

 

History

History
166 lines (126 loc) · 4.29 KB

File metadata and controls

166 lines (126 loc) · 4.29 KB

Error system

v0.15 state: type-directed lowering throughout, Go generics on parametric record aliases. Layer-3 stdlib, whole-program DCE (Stripe-SDK scale: −82 % source), LSP 100 % coverage; runtime verification across all 27 examples (120 stdlib assertions + 306 cabal specs). See ../compiler/versions.md for the changelog.

Since v0.9, every fallible operation in Sky returns a value whose error slot is Sky.Core.Error — a structured ADT with eleven kinds and typed details. There is no more Result String or Task String on any public surface.

The shape

module Sky.Core.Error exposing (..)


type Error
    = Error ErrorKind ErrorInfo


type ErrorKind
    = Io
    | Network
    | Ffi
    | Decode
    | Timeout
    | NotFound
    | PermissionDenied
    | InvalidInput
    | Conflict
    | Unavailable
    | Unexpected


type alias ErrorInfo =
    { message : String
    , details : ErrorDetails
    }


type ErrorDetails
    = NoDetails
    | FfiPanic String
    | TypeMismatch String String
    | HttpStatus Int
    | JsonDecode String
    | Custom (Dict String String)

Constructors

io : String -> Error
network : String -> Error
ffi : String -> Error
decode : String -> Error
timeout : String -> Error
notFound : Error
permissionDenied : Error
invalidInput : String -> Error
conflict : String -> Error
unavailable : String -> Error
unexpected : String -> Error

Plus builders:

withMessage : String -> Error -> Error
withDetails : ErrorDetails -> Error -> Error
toString : Error -> String
isRetryable : Error -> Bool

Usage pattern

import Sky.Core.Error as Error exposing (Error(..), ErrorKind(..))


loadUser : Db -> String -> Task Error (List User)
loadUser db id =
    Db.queryDecode db "SELECT * FROM users WHERE id = ?" [ id ] userDecoder
        |> Task.mapError classifyError


classifyError : Error -> Error
classifyError e =
    case e of
        Error PermissionDenied info ->
            info.message
                |> String.append "user lacks permission: "
                |> Error.invalidInput
        _ ->
            e

Go side

Every runtime kernel that can fail returns rt.SkyResult[any, any] where the Err slot is a value produced by one of the Err* builders in runtime-go/rt/rt.go:

ErrIo(msg string) any
ErrNetwork(msg string) any
ErrFfi(msg string) any
ErrDecode(msg string) any
ErrTimeout(msg string) any
ErrNotFound() any
ErrPermissionDenied() any
ErrInvalidInput(msg string) any
ErrConflict(msg string) any
ErrUnavailable(msg string) any
ErrUnexpected(msg string) any

These produce skyErrorAdt values that match the Sky ADT's runtime layout ({Tag, SkyName, V0 (kind), V1 (info)}), so Sky-side pattern matching works without a translation layer.

Panic recovery

func SkyFfiRecover(out *any) func()
func SkyFfiRecoverT[A any](out *SkyResult[any, A]) func()

Every FFI wrapper defers one of these. On panic, out is set to Err(ErrFfi(<panic-message>)) with an FfiPanic detail carrying the recovered value. Sky code never sees a Go panic.

When to use which kind

Kind Use for
Io File / DB / disk failures
Network HTTP / DNS / transport failures
Ffi Panics caught at the FFI boundary
Decode JSON / binary decoder failures
Timeout Deadlines, context cancellation
NotFound Record or resource absent
PermissionDenied Auth / access-control failures
InvalidInput User input validation
Conflict Optimistic-lock / unique-constraint failures
Unavailable Service overloaded / circuit-broken
Unexpected Fallback when no other kind fits

isRetryable returns True for Timeout, Network, and Unavailable. Use it in retry / backoff policies.

Migration from Result String

If you're upgrading a pre-v1 project:

-- Before:
loadUser : String -> Task String User

-- After:
loadUser : String -> Task Error User

If your error branch was Err e -> Err (Error.io e) and the upstream now returns Error (not String), collapse to Err e -> Err e. Error chaining through combinators preserves the kind.

Forbidden in v0.9+ public surfaces (enforced by Sky.ErrorUnificationSpec):

  • Result String a
  • Task String a
  • Std.IoError (deleted)
  • RemoteData (deleted)