Error Handling
zchrome uses Zig's error handling system with categorized error sets for different failure modes.
Error Categories
TransportError
Network and WebSocket errors:
zig
pub const TransportError = error{
ConnectionRefused, // Chrome not reachable
ConnectionClosed, // Connection dropped
ConnectionReset, // Connection reset by peer
HandshakeFailed, // WebSocket handshake failed
TlsError, // TLS/SSL error
FrameTooLarge, // WebSocket frame exceeds limit
InvalidFrame, // Malformed WebSocket frame
Timeout, // Operation timed out
};ProtocolError
CDP message parsing errors:
zig
pub const ProtocolError = error{
InvalidMessage, // Malformed JSON-RPC message
UnexpectedResponse, // Response doesn't match request
MissingField, // Required field not present
TypeMismatch, // Field has unexpected type
};CdpError
Chrome DevTools Protocol errors:
zig
pub const CdpError = error{
TargetCrashed, // Target (page) crashed
TargetClosed, // Target was closed
SessionNotFound, // Session ID invalid
MethodNotFound, // CDP method doesn't exist
InvalidParams, // Invalid method parameters
InternalError, // Chrome internal error
GenericCdpError, // Other CDP error
};LaunchError
Browser startup errors:
zig
pub const LaunchError = error{
ChromeNotFound, // Chrome executable not found
LaunchFailed, // Failed to start process
WsUrlParseError, // Couldn't parse WebSocket URL
StartupTimeout, // Chrome didn't start in time
};Error Handling Patterns
Basic Try-Catch
zig
const result = page.navigate(allocator, url) catch |err| {
std.debug.print("Navigation failed: {}\n", .{err});
return err;
};Switch on Error
zig
var browser = cdp.Browser.launch(.{ ... }) catch |err| switch (err) {
error.ChromeNotFound => {
std.debug.print("Chrome not found!\n", .{});
std.debug.print("Install Chrome or specify path with --chrome\n", .{});
std.process.exit(1);
},
error.StartupTimeout => {
std.debug.print("Chrome startup timed out. Try increasing timeout.\n", .{});
std.process.exit(1);
},
error.ConnectionRefused => {
std.debug.print("Could not connect to Chrome.\n", .{});
std.process.exit(1);
},
else => {
std.debug.print("Unexpected error: {}\n", .{err});
return err;
},
};Handling Navigation Errors
Navigation can fail even without throwing:
zig
var result = try page.navigate(allocator, url);
defer result.deinit(allocator);
if (result.error_text) |err_text| {
std.debug.print("Navigation error: {s}\n", .{err_text});
// Handle: net::ERR_NAME_NOT_RESOLVED, net::ERR_CONNECTION_REFUSED, etc.
return;
}
std.debug.print("Successfully navigated to frame: {s}\n", .{result.frame_id});Handling JavaScript Errors
zig
var result = try runtime.evaluate(allocator, expression, .{
.return_by_value = true,
});
defer result.deinit(allocator);
if (result.exception_details) |exception| {
std.debug.print("JavaScript error: {s}\n", .{exception.text});
return;
}Graceful Session Cleanup
zig
var session = try browser.newPage();
defer {
// Use catch {} to ignore errors during cleanup
session.detach() catch {};
}Timeout Handling
Launch Timeout
zig
var browser = try cdp.Browser.launch(.{
.timeout_ms = 60_000, // 60 second timeout
.allocator = allocator,
.io = init.io,
});Command Timeout
Commands use the connection's receive timeout:
zig
const connection = try Connection.open(ws_url, .{
.allocator = allocator,
.io = init.io,
.receive_timeout_ms = 30_000, // 30 seconds per command
});Retry Logic
zchrome includes a retry utility:
zig
const retry = @import("cdp").retry;
// Retry with exponential backoff
const result = try retry.withBackoff(3, struct {
fn attempt() !Response {
return session.sendCommand("Page.navigate", .{ .url = url });
}
}.attempt);Common Error Scenarios
Chrome Not Found
zig
if (cdp.Browser.launch(.{ ... })) |browser| {
// Success
} else |err| if (err == error.ChromeNotFound) {
// Suggest installation or manual path
}Target Crashed
zig
const result = page.captureScreenshot(allocator, .{}) catch |err| {
if (err == error.TargetCrashed) {
// Page crashed, create new page
session.detach() catch {};
var new_session = try browser.newPage();
// Retry operation
}
return err;
};Connection Lost
zig
while (true) {
const cmd_result = session.sendCommand("Page.navigate", .{ .url = url }) catch |err| {
if (err == error.ConnectionClosed or err == error.ConnectionReset) {
// Reconnect
browser.close();
browser = try cdp.Browser.launch(.{ ... });
session = try browser.newPage();
continue;
}
return err;
};
break;
}Best Practices
Always use defer for cleanup
zigvar browser = try cdp.Browser.launch(.{ ... }); defer browser.close();Check NavigateResult.error_text
zigif (result.error_text) |err| { // Handle navigation failure }Handle session detach errors gracefully
zigdefer session.detach() catch {};Set appropriate timeouts
zig.timeout_ms = 60_000, // For slow pagesLog errors with context
zigstd.debug.print("Failed to navigate to {s}: {}\n", .{url, err});