Exceptions and Errors

The :std/error library provides base classes for exceptions and errors.

usage

(import :std/error)

The root of the hierarchy

The exception hierarchy is rooted in two base classes: Error and Exception.

  • Instances of Error indicate error conditions, and they have a standard payload of a message, a subsystem or procedure name where the error originated, and a list of irritants. Error mixes in StackTrace which allows the system to fill stack traces -- see raise below.
  • Instances of Exception indicate exceptional conditions that are not necessarily errors, and do not have a standard payload. Exception does not mix StackTrace, as it is possible to use Exception instances for control flow, in which case it would be inappropriate to include stack traces without the programmer's consent.

Exception

(defclass Exception ...)

The base class for naked exception objects; there are no fields or slots in this class.

Exception?

(Exception? obj)

Predicate for Exception instances

RuntimeException

(defclass (RuntimeException Exception ...) ...)

Wrapper class for exceptions generated by the gambit runtime, such that a stack trace can be attached.

The original exception is available at the exception slot.

RuntimeException?

(RuntimeException? obj)

Predicate for RuntimeException instances.

StackTrace

(defclass StackTrace (continuation))

Mixin class for stack traces in errors.

If an exception class that mixes in StackTrace is raised by this module's redefined raise (see below), then the current continuation will be captured (if not already captured) and stored in the continuation slot. The continuation backtrace will be displayed by Error::display-exception to facilitate debugging.

StackTrace?

StackTrace?

Predicate for StackTrace mixins.

Error

(defclass (Error StackTrace ...) ...)

(Error message irritants: (irritants []) where: (where #f))

The base class for errors.

The constructor takes a required argument (message) and two optional keyword arguments:

  • message; this the error message to display to the user.
  • irritants; this is a list of objects related to the error condition.
  • where; this is usually a symbol (may be false) indicating the source of the error.

Error?

(Error? obj)

Predicate for Error instances.

Error-message

(Error-message err) -> string
  err := instance of Error

Accessor for the error message.

Error-irritants

(Error-irritants err) -> list
  err := instance of Error

Accessor for the error irritants.

Error-where

(Error-where err) -> any
  err := instance of Error

Accessor for the error origin.

Error:::init!

(Error:::init! err message irritants: (irritants []) where: (where #f))
  err := instance of Error

The base Error constructor, which error subclasses can call to initialize the base error reprsentation.

Error::display-exception

(Error::display-exception err port)
  err  := instance of Error
  port := output port

Base method for displaying Errors, including a stack trace if available; see StackTrace below.

Standard Error Classes

The following are predefined classes with standard semantics, used througout the standard library.

ContractViolation

(defclass (ContractViolation StackTrace Error) ())

Error indicating an input parameter contract violation condition.

ContractViolation?

(ContractViolation? exn)

Predicate testing whether the error is a contract violation condition.

contract-violation-error?

(def contract-violation-error! ContractViolation?)

Same as ContractViolation?.

IOError

(defclass (IOError StackTrace Error) ())

Error indicating an IO condition.

IOError?

(IOError? exn)

Predicate testing whether the error is an IO condition.

io-error?

(def io-error? IOError?

same as IOError?

PrematureEndOfInput

(defclass (PrematureEndOfInput IOError) ())

Error indicating that input was exhausted prematurely; similar to EOF exceptions in other languages.

PrematureEndOfInput?

(PrematureEndOfInput? obj)

Predicate testing whether the error is a premature end of input condition.

premature-end-of-input-error?

(def permature-end-of-input? PrematureEndOfInput?)

Same as PrematureEndOfInput?.

IOClosed

(deferror-class (IOClosed IOError))

Error indicating that the IO sink or source has been closed and thus no further IO operations can be performed.

IOClosed?

(IOClosed? obj)

Predicate testing whether the error is an IO closed condition.

io-closed-error?

(def io-closed-error? IOClosed?)

Same as IOClosed?.

Timeout

(deferror-class Timeout)

Error indicating that some operation has timed out.

Timeout?

(Timeout? obj)

Predicate testing whether the error is a timeout.

timeout-error?

(def timeout-error? Timeout?)

Same as Timeout?.

ContextError

(deferror-class ContextError)

Error indicating that some operation was performed out of context.

ContextError?

(ContextError? obj)

Predicate testing whether the error is a context error

context-error?

(def context-error? ContextError?)

Same as ContextError?.

UnboundKey

(deferror-class UnboundKey)

Error indicating that some lookup operation failed because a key was unbound.

UnboundKey?

(UnboundKey? obj)

Predicate testing whether the condition is an unbound key error

unbound-key-error?

(def unbound-key-error? UnboundKey?)

Same as UnboundKey?.

Raising exceptions

The library redefines raise and error so that it fills stack traces where appropriate. It also provides some utility procedure for raising particular errors without caring about the particulars of the condition system.

error

(error message irritant ...)

Like basic Scheme's error, but raises with stack trace.

raise

(raise exn)

Raises an exception condition.

If the exception object is an instance of StackTrace, then unless there is already a continuation because this is a re-raise, the continuation is captured and stored in the continuation slot.

check-argument

(check-argument expr expectation argument)
  expr := a boolean expression
  expectation := a string describing the expectation
  argument := the argument being checked for reporting purposes.

Evaluates the boolean expression expr and raises a contract violation if it is #f.

raise-contract-violation

(raise-contract-violation where contract irritant ...)

Raises a ContractViolation condition.

raise-io-error

(raise-io-error where message . irritants)

Raises an IOError condition.

raise-premature-end-of-input

(raise-premature-end-of-input where . irritants)

p Raises a PrematureEndOfInput condition.

raise-io-closed

(raise-io-closed where message . irritants)

Raises an IOClosed condition.

raise-timeout

(raise-timeout where message . irritants)

Raises a Timeout condition.

raise-context-error

(raise-context-error where message . irritants)

Raise a ContextError condition.

raise-key-error

(raise-key-error where message . irritants)

Raise a KeyError condition.

BUGS

Sometimes something that really shouldn't happen, but it did; because, Murphy.

BUG

(BUG where message . irritants)

Raise a bug condition.

is-it-bug?

(is-it-bug? obj)

Checks whether an error condition was caused by a something unexpected, a bug.

Defining custom Error classes

The library offers a utility macro to define error classes that follow the standard library conventions. You don't have to use it, but if you are building a library it is recommended to do so.

deferror-class

(deferror-class Class slots predicate-alias [constructor = Error:::init!])
(deferror-class (Class Mixin ...) slots predicate-alias [constructor = Error:::init!])

The first form defines a class Class with slots slots that extends Error, mixing in StackTrace. It also defines a predicate alias for the class's instance predicate that can be exported to hide the internal error details.

Dumping stack traces

It is useful to invoke a thunk and dump an exception stack trace if it raises; this can be accomplished with the with-exception-stack-trace and dump-stack-trace! utility procedures.

This can be useful when you are dealing with exceptions that do not mixin StackTrace (which will automatically dump the stack trace when displaying the exception with display-exception).

with-exception-stack-trace

(with-exception-stack-trace thunk (error-port (current-error-port)))

Invokes thunk with an exception handler that dumps the exception stack trace with dump-stack-trace! if (dump-stack-trace?) is true (the default).

dump-stack-trace?

(define dump-stack-trace? (make-parameter #t))

A parameter that controls whether some a stack trace will be dumped when an exception is presented to the user.

This parameter is notably used by the display-exception method for the Error type in the runtime, and by with-exception-stack-trace (see above) that is also used in the default exception handler installed in threads spawned with spawn-actor. It is also heeded by exit-with-error (see below).

You can (dump-stack-trace? #f) or locally (parameterize ((dump-stack-trace? #f)) ...) to disable this stack trace dump, in case you are building a program for end-users rather than for developers, and want to control what limited error output they see. Or you can re-enable them based on a debug flag at the CLI in cases you want them to provide you with extra debugging information, or log bug reports directly to your servers, etc.

dump-stack-trace!

(dump-stack-trace! cont exn (error-port (current-error-port)))

Displays the exception exn, dumping the stack trace of continuation cont if there is no stack trace information in the exception itself.

exit-with-error

(exit-with-error exception) => [exit]

Display the exception to current error port and exit with error code 2.

exit-on-error?

(def exit-on-error? (make-parameter #t))

This parameter controls whether call-with-exit-on-error, with-exit-on-error, call-with-getopt, and any function that indirectly uses them, will exit if an error is caught, rather than pass on the error and return to the REPL (or let a more fundamental function exit).

If dump-stack-trace? is true, then the exception will be reprinted a second time with dump-stack-trace? bound to false, so that the text of the exception should be printed a second time after the stack dump.

call-with-exit-on-error

(call-with-exit-on-error thunk)

Calls the thunk in an environment wherein if an error is caught and (exit-on-error) is true, exit-with-error will be called, causing an error message to be printed and the process to exit with exit code 2. If (exit-on-error) is false, the error will simply be raised again.

This mechanism enables users to modify the parameter (e.g. via a flag passed at the Unix CLI or a change made at the Scheme REPL) and control whether to exit with an error (e.g. for end-users) or enter a debugger REPL (e.g. for developers).

with-exit-on-error

(with-exit-on-error body ...)

Evaluates the body as in a thunk passed to call-with-exit-on-error.