Error Codes
v0.2.0 introduces structured error handling with error codes and detailed messages.
BoxliteErrorCode
All API functions return BoxliteErrorCode to indicate success or failure type:
typedef enum BoxliteErrorCode {
Ok = 0, // Success
Internal = 1, // Internal error
NotFound = 2, // Resource not found
AlreadyExists = 3, // Resource already exists
InvalidState = 4, // Invalid state for operation
InvalidArgument = 5, // Invalid argument
Config = 6, // Configuration error
Storage = 7, // Storage error
Image = 8, // Image error
Network = 9, // Network error
Execution = 10, // Execution error
Stopped = 11, // Resource stopped
Engine = 12, // Engine error
Unsupported = 13, // Unsupported operation
Database = 14, // Database error
Portal = 15, // Portal/communication error
Rpc = 16, // RPC error
} BoxliteErrorCode;
Error Code Reference
| Code | Name | Value | Description |
|---|
Ok | Success | 0 | Operation completed successfully |
Internal | Internal Error | 1 | An internal error occurred |
NotFound | Not Found | 2 | The requested resource was not found |
AlreadyExists | Already Exists | 3 | The resource already exists |
InvalidState | Invalid State | 4 | The resource is in an invalid state for the operation |
InvalidArgument | Invalid Argument | 5 | An invalid argument was provided |
Config | Configuration Error | 6 | A configuration error occurred |
Storage | Storage Error | 7 | A storage error occurred |
Image | Image Error | 8 | An image-related error occurred |
Network | Network Error | 9 | A network error occurred |
Execution | Execution Error | 10 | A command execution error occurred |
Stopped | Stopped | 11 | The resource is stopped |
Engine | Engine Error | 12 | A VM engine error occurred |
Unsupported | Unsupported | 13 | The operation is not supported |
Database | Database Error | 14 | A database error occurred |
Portal | Portal Error | 15 | A portal/communication error occurred |
Rpc | RPC Error | 16 | An RPC error occurred |
CBoxliteError
Detailed error information for debugging:
typedef struct CBoxliteError {
BoxliteErrorCode code; // Error code for programmatic handling
char* message; // Detailed message (NULL if none)
} CBoxliteError;
Always initialize CBoxliteError with zero: CBoxliteError error = {0};. The struct is stack-allocated, but the message field points to heap memory that must be freed with boxlite_error_free().
Error Handling Functions
boxlite_error_free
Free error struct (message only - struct itself is stack-allocated).
void boxlite_error_free(CBoxliteError* error);
Safe to call with NULL. After calling, the message field is set to NULL.
Error Handling Patterns
Pattern 1: Basic Check
CBoxliteError error = {0};
BoxliteErrorCode code = boxlite_simple_new("alpine:3.19", 0, 0, &box, &error);
if (code != Ok) {
fprintf(stderr, "Error %d: %s\n", error.code, error.message);
boxlite_error_free(&error);
return 1;
}
Pattern 2: Switch on Error Code
BoxliteErrorCode code = boxlite_get(runtime, "box-id", &box, &error);
switch (code) {
case Ok:
// Success - use box
break;
case NotFound:
fprintf(stderr, "Box not found\n");
break;
case InvalidState:
fprintf(stderr, "Box in invalid state\n");
break;
default:
fprintf(stderr, "Error %d: %s\n", error.code, error.message);
}
boxlite_error_free(&error);
Pattern 3: Retry Logic
int retries = 3;
for (int i = 0; i < retries; i++) {
code = boxlite_simple_new("alpine:3.19", 0, 0, &box, &error);
if (code == Ok) break;
fprintf(stderr, "Retry %d/%d: %s\n", i+1, retries, error.message);
boxlite_error_free(&error);
if (code == InvalidArgument || code == Unsupported) {
break; // Non-retryable errors
}
sleep(1); // Backoff
}
Some error codes like InvalidArgument and Unsupported indicate permanent failures that should not be retried. Check the error code before retrying.
Pattern 4: Cleanup on Error
CBoxliteRuntime* runtime = NULL;
CBoxHandle* box = NULL;
CBoxliteError error = {0};
if (boxlite_runtime_new(NULL, NULL, &runtime, &error) != Ok) {
fprintf(stderr, "Runtime error: %s\n", error.message);
boxlite_error_free(&error);
return 1;
}
const char* options = "{"
"\"rootfs\":{\"Image\":\"alpine:3.19\"},"
"\"env\":[],\"volumes\":[],\"network\":\"Isolated\",\"ports\":[]"
"}";
if (boxlite_create_box(runtime, options, &box, &error) != Ok) {
fprintf(stderr, "Box error: %s\n", error.message);
boxlite_error_free(&error);
boxlite_runtime_free(runtime); // Clean up runtime before exit
return 1;
}
// Use box...
boxlite_runtime_free(runtime); // Frees runtime and all boxes
Metrics
boxlite_runtime_metrics
Get runtime-wide metrics as JSON.
BoxliteErrorCode boxlite_runtime_metrics(
CBoxliteRuntime* runtime,
char** out_json,
CBoxliteError* out_error
);
Parameters
| Parameter | Type | Description |
|---|
runtime | CBoxliteRuntime* | Runtime instance |
out_json | char** | Output: JSON string (caller must free with boxlite_free_string()) |
out_error | CBoxliteError* | Output: error information |
Example Output
{
"boxes_created_total": 10,
"boxes_failed_total": 0,
"num_running_boxes": 2,
"total_commands_executed": 42,
"total_exec_errors": 1
}
Runtime Metrics Fields
| Field | Type | Description |
|---|
boxes_created_total | integer | Total number of boxes created since runtime start |
boxes_failed_total | integer | Total number of box creation failures |
num_running_boxes | integer | Current number of running boxes |
total_commands_executed | integer | Total commands executed across all boxes |
total_exec_errors | integer | Total command execution errors |
Example
char* metrics_json = NULL;
CBoxliteError error = {0};
if (boxlite_runtime_metrics(runtime, &metrics_json, &error) == Ok) {
printf("Runtime metrics: %s\n", metrics_json);
boxlite_free_string(metrics_json);
} else {
fprintf(stderr, "Error: %s\n", error.message);
boxlite_error_free(&error);
}
boxlite_box_metrics
Get per-box metrics as JSON.
BoxliteErrorCode boxlite_box_metrics(
CBoxHandle* handle,
char** out_json,
CBoxliteError* out_error
);
Parameters
| Parameter | Type | Description |
|---|
handle | CBoxHandle* | Box handle |
out_json | char** | Output: JSON string (caller must free with boxlite_free_string()) |
out_error | CBoxliteError* | Output: error information |
Example Output
{
"cpu_percent": 5.2,
"memory_bytes": 12582912,
"commands_executed_total": 10,
"exec_errors_total": 0,
"bytes_sent_total": 1024,
"bytes_received_total": 2048,
"total_create_duration_ms": 1234,
"guest_boot_duration_ms": 567
}
Box Metrics Fields
| Field | Type | Description |
|---|
cpu_percent | float | Current CPU usage percentage |
memory_bytes | integer | Current memory usage in bytes |
commands_executed_total | integer | Total commands executed in this box |
exec_errors_total | integer | Total execution errors in this box |
bytes_sent_total | integer | Total network bytes sent |
bytes_received_total | integer | Total network bytes received |
total_create_duration_ms | integer | Time taken to create the box (ms) |
guest_boot_duration_ms | integer | Time taken for guest OS to boot (ms) |
Example
char* metrics_json = NULL;
CBoxliteError error = {0};
if (boxlite_box_metrics(box, &metrics_json, &error) == Ok) {
printf("Box metrics: %s\n", metrics_json);
boxlite_free_string(metrics_json);
} else {
fprintf(stderr, "Error: %s\n", error.message);
boxlite_error_free(&error);
}
Complete Metrics Example
#include <stdio.h>
#include "boxlite.h"
int main() {
CBoxliteRuntime* runtime = NULL;
CBoxHandle* box = NULL;
CBoxliteError error = {0};
char* json = NULL;
// Setup runtime and box
boxlite_runtime_new(NULL, NULL, &runtime, &error);
const char* options = "{"
"\"rootfs\":{\"Image\":\"alpine:3.19\"},"
"\"env\":[],\"volumes\":[],\"network\":\"Isolated\",\"ports\":[]"
"}";
boxlite_create_box(runtime, options, &box, &error);
// Execute some commands
int exit_code = 0;
boxlite_execute(box, "echo", "[\"hello\"]", NULL, NULL, &exit_code, &error);
boxlite_execute(box, "ls", "[\"/\"]", NULL, NULL, &exit_code, &error);
// Check runtime metrics
if (boxlite_runtime_metrics(runtime, &json, &error) == Ok) {
printf("Runtime metrics:\n%s\n\n", json);
boxlite_free_string(json);
}
// Check box metrics
if (boxlite_box_metrics(box, &json, &error) == Ok) {
printf("Box metrics:\n%s\n", json);
boxlite_free_string(json);
}
// Cleanup
boxlite_runtime_free(runtime);
return 0;
}