Skip to main content

playwright_rs/
error.rs

1// Error types for playwright-core
2
3use thiserror::Error;
4
5/// Result type alias for playwright-core operations
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Errors that can occur when using playwright-core
9#[derive(Debug, Error)]
10#[non_exhaustive]
11pub enum Error {
12    /// Playwright server binary was not found
13    ///
14    /// The Playwright Node.js driver could not be located.
15    /// To resolve this, install Playwright using: `npm install playwright`
16    /// Or ensure the PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD environment variable is not set.
17    #[error("Playwright server not found. Install with: npm install playwright")]
18    ServerNotFound,
19
20    /// Failed to launch the Playwright server process
21    ///
22    /// The Playwright server process could not be started.
23    /// Common causes: Node.js not installed, insufficient permissions, or port already in use.
24    /// Details: {0}
25    #[error("Failed to launch Playwright server: {0}. Check that Node.js is installed.")]
26    LaunchFailed(String),
27
28    /// Server error (runtime issue with Playwright server)
29    #[error("Server error: {0}")]
30    ServerError(String),
31
32    /// Browser is not installed
33    ///
34    /// The specified browser has not been installed for the bundled driver.
35    /// To resolve this, install browsers through the crate (version-safe), or
36    /// with the one-off npx command using the exact bundled driver version.
37    #[error(
38        "Browser '{browser_name}' is not installed.\n\n\
39        {message}\n\n\
40        To install {browser_name} from your project (version-safe, rides Cargo.lock):\n  \
41        playwright_rs::install_browsers(Some(&[\"{browser_name}\"])).await\n  \
42        (see the crate's install-browsers example)\n\n\
43        Or as a one-off shell command:\n  \
44        npx playwright@{playwright_version} install {browser_name}\n  \
45        (the version must match the bundled driver; avoid hardcoding it in CI)\n\n\
46        See: https://playwright.dev/docs/browsers"
47    )]
48    BrowserNotInstalled {
49        browser_name: String,
50        message: String,
51        playwright_version: String,
52    },
53
54    /// Failed to establish connection with the server
55    #[error("Failed to connect to Playwright server: {0}")]
56    ConnectionFailed(String),
57
58    /// Transport-level error (stdio communication)
59    #[error("Transport error: {0}")]
60    TransportError(String),
61
62    /// Protocol-level error (JSON-RPC)
63    #[error("Protocol error: {0}")]
64    ProtocolError(String),
65
66    /// I/O error
67    #[error("I/O error: {0}")]
68    Io(#[from] std::io::Error),
69
70    /// JSON serialization/deserialization error
71    #[error("JSON error: {0}")]
72    Json(#[from] serde_json::Error),
73
74    /// Timeout waiting for operation
75    ///
76    /// Contains context about what operation timed out and the timeout duration.
77    /// Common causes include slow network, server not responding, or element not becoming actionable.
78    /// Consider increasing the timeout or checking if the target is accessible.
79    #[error("Timeout: {0}")]
80    Timeout(String),
81
82    /// Navigation timeout
83    ///
84    /// Occurs when page navigation exceeds the specified timeout.
85    /// Includes the URL being navigated to and timeout duration.
86    #[error("Navigation timeout after {duration_ms}ms navigating to '{url}'")]
87    NavigationTimeout { url: String, duration_ms: u64 },
88
89    /// Target was closed (browser, context, or page)
90    ///
91    /// Occurs when attempting to perform an operation on a closed target.
92    /// The target must be recreated before it can be used again.
93    #[error("Target closed: Cannot perform operation on closed {target_type}. {context}")]
94    TargetClosed {
95        target_type: String,
96        context: String,
97    },
98
99    /// Unknown protocol object type
100    #[error("Unknown protocol object type: {0}")]
101    UnknownObjectType(String),
102
103    /// Channel closed unexpectedly
104    #[error("Channel closed unexpectedly")]
105    ChannelClosed,
106
107    /// Invalid argument provided to method
108    #[error("Invalid argument: {0}")]
109    InvalidArgument(String),
110
111    /// Element not found by selector
112    ///
113    /// Includes the selector that was used to locate the element.
114    /// This error typically occurs when waiting for an element times out.
115    #[error("Element not found: selector '{0}'")]
116    ElementNotFound(String),
117
118    /// Assertion timeout (expect API)
119    #[error("Assertion timeout: {0}")]
120    AssertionTimeout(String),
121
122    /// Assertion failed (expect API, server returned mismatch without timeout)
123    #[error("Assertion failed: {0}")]
124    AssertionFailed(String),
125    /// Object not found in registry (may have been closed/disposed)
126    #[error("Object not found (may have been closed): {0}")]
127    ObjectNotFound(String),
128
129    /// Type mismatch when downcasting a protocol object
130    ///
131    /// Occurs when a protocol object's concrete type does not match the expected type.
132    /// This typically indicates a Playwright protocol version mismatch or a bug in the
133    /// object factory.
134    #[error("Type mismatch for object '{guid}': expected {expected}, got {actual}")]
135    TypeMismatch {
136        guid: String,
137        expected: String,
138        actual: String,
139    },
140
141    /// Invalid path provided
142    #[error("Invalid path: {0}")]
143    InvalidPath(String),
144
145    /// Error with additional context
146    #[error("{0}: {1}")]
147    Context(String, #[source] Box<Error>),
148}
149
150impl Error {
151    /// Adds context to the error
152    pub fn context(self, msg: impl Into<String>) -> Self {
153        Error::Context(msg.into(), Box::new(self))
154    }
155}