Skip to content

Error Handling

Lee Yunjin edited this page Oct 7, 2026 · 1 revision

Error Handling

Header: <cwist/sys/err/cwist_err.h>

cwist_error_t

Most CWIST functions return a cwist_error_t: a tagged value whose errtype says which member of the union is active.

typedef struct cwist_error_t {
    cwist_errtype_t errtype;    /* CWIST_ERR_INT8, _INT16, _INT32, _INT64, _UINT*, _STRING, _JSON, ... */
    __prim_cwist_error_t error; /* err_i8, err_i16, err_i32, err_i64, err_u*, err_string, err_json */
} cwist_error_t;

Most APIs use the 16-bit channel (CWIST_ERR_INT16, err.error.err_i16). Some return a JSON payload (CWIST_ERR_JSON, err.error.err_json) with details from OpenSSL or SQLite.

Checking for success

Always use cwist_error_is_ok():

cwist_error_t err = cwist_db_exec(db, "CREATE TABLE t(x)");
if (!cwist_error_is_ok(&err)) {
    /* failure */
    cwist_error_dispose(&err);
}

Success means the active channel holds its zero or empty value. Open-coding a check such as err.error.err_i16 != 0 reads the wrong union member whenever a function uses another channel, which has caused success to be reported as failure before. cwist_error_is_ok(NULL) is true.

Function Description
static inline bool cwist_error_is_ok(const cwist_error_t *err) True on success.
bool cwist_error_is_ok_extern(const cwist_error_t *err) Same check as a real symbol, for bindings that cannot call static inline functions.
void cwist_error_dispose(cwist_error_t *err) Release memory owned by an error value. Only CWIST_ERR_JSON owns memory today; safe on success values and NULL.
cwist_error_t make_error(cwist_errtype_t type) Create a zeroed error of a given type (for your own functions).

Common codes

Constant Value Meaning
CWIST_SUCCESS 0 success
CWIST_FAILURE -1 generic failure
CWIST_ERROR_IO -2 I/O, network or TLS error
CWIST_ERROR_NOMEM -3 allocation failure
CWIST_ERROR_INVALID_PARAM -4 invalid argument
CWIST_ERROR_PROTOCOL -5 protocol violation
CWIST_ERROR_TIMEOUT -6 timeout

128-bit channels exist when the library is built with USE_128BIT_ERRCODE on GCC or Clang.

Other return conventions

Not every function uses cwist_error_t. Many return int (0 or -1, or a negative errno), bool, or a pointer that is NULL on failure. Each module page states the convention for its functions.

HTTP errors

  • A handler reports an HTTP error by setting res->status_code and a body.
  • When no route, asset or static file matches, the app calls the error handler registered for 404 or the fallback handler set with cwist_app_set_error_handler(); without one it answers 404 Not Found. See Application.
  • Protocol errors in a request (malformed request line, oversized headers or body, unsupported transfer coding) are answered by the server before the handler runs; see Requests and Responses.
  • Validation can write a 400 JSON error response for you.
static void not_found(cwist_http_request *req, cwist_http_response *res,
                      cwist_http_status_t status) {
    (void)req;
    res->status_code = status;
    cwist_http_header_add(&res->headers, "Content-Type", "application/json");
    cwist_sstring_assign(res->body, "{\"error\":\"not found\"}");
}

cwist_app_register_error_handler(app, CWIST_HTTP_NOT_FOUND, not_found);

Unused parameters

CWIST_UNUSED(x) from <cwist/core/macros.h> silences unused-parameter warnings in handlers.

Clone this wiki locally