ElementResolutionError in ego-lite: Handling Transient and Permanent Resolution Failures
ElementResolutionError is a custom error class in ego-lite that classifies resolution failures as either transient (retryable) or permanent (fatal), enabling automation scripts to implement intelligent retry logic.
ElementResolutionError powers the element-resolution subsystem in ego-lite, an open-source browser automation framework maintained by CitroLabs. Defined in src/element-resolver.ts, this error provides granular failure classification that distinguishes between DOM elements that may appear after a short delay versus fundamentally broken or ambiguous selectors.
What is ElementResolutionError?
ElementResolutionError extends the native JavaScript Error class to signal specific failure modes during element resolution. According to the ego-lite source code, the runtime throws this error whenever it cannot locate or interact with a target element using the supplied selector or reference.
The class exposes a kind property that communicates whether the failure is recoverable. This design pattern allows calling code in src/driver/waits.ts and src/driver/locator.ts to implement polling loops that differentiate between temporary DOM states and permanent configuration errors.
The Two Kinds of ElementResolutionError
The error type discriminates between two distinct failure modes through its string-literal kind property.
Transient Errors (Retryable)
A transient error indicates that the element might become available if the script waits briefly. This kind covers scenarios where:
- The element is still loading or rendering
- The element exists in the DOM but is temporarily hidden
- The DOM reference has become stale and needs refresh
- Box-model data is not yet computed
The wait logic in src/driver/waits.ts specifically checks for err.kind === "transient" to continue polling rather than aborting the operation.
Permanent Errors (Non-Retryable)
A permanent error signals that retries would be wasteful because the selector itself is invalid or ambiguous. This kind triggers when:
- The selector syntax is malformed or evaluates to an exception
- The query matches multiple elements when exactly one is required
- Required attributes are missing or immutable
Catching a permanent error allows scripts to fail fast with descriptive messaging rather than consuming resources on futile polling attempts.
Class Implementation in element-resolver.ts
The error class is implemented in src/element-resolver.ts with a straightforward constructor that accepts a message and kind discriminator:
export class ElementResolutionError extends Error {
kind: "transient" | "permanent";
constructor(message: string, kind: "transient" | "permanent") {
super(message);
this.name = "ElementResolutionError";
this.kind = kind;
}
}
This structure enables TypeScript's type narrowing and allows runtime inspection via instanceof checks.
Where ElementResolutionError is Raised
The ego-lite codebase raises ElementResolutionError in four primary contexts:
- Selector parsing — Thrown as
selectorResolutionErrorwhen a selector evaluates to an exception or matches an invalid number of elements - Reference look-up — Triggered when a numeric reference (
@N) is unknown or its backend node is stale, typically returningtransientfor "Unknown ref" scenarios - AX role/name lookup — Returns
transientfor zero matches (element may appear) butpermanentfor ambiguous matches exceeding one element - Box-model extraction — Raises
transientwhen an element lacks a usable box model, indicating the layout calculation is incomplete
Practical Error Handling Patterns
The following patterns demonstrate how to catch and respond to ElementResolutionError based on its kind.
Example: Conditional retry logic
import { ElementResolutionError } from "./element-resolver.js";
try {
const { x, y } = await resolveElementCenter(cdp, sessionId, refMap, "#submit");
// … use coordinates …
} catch (err) {
if (err instanceof ElementResolutionError) {
if (err.kind === "transient") {
// Retry later – element may appear after a short delay
await delay(200);
return resolveElementCenter(cdp, sessionId, refMap, "#submit");
}
// Permanent – selector is wrong, abort with a helpful message
console.error("Permanent resolution failure:", err.message);
} else {
throw err; // re‑throw unexpected errors
}
}
Example: Integration with wait utilities
import { waitFor } from "./driver/waits.js";
await waitFor(async () => {
try {
await resolveElementCenter(cdp, sessionId, refMap, "role:button[name=Submit]");
return true; // success
} catch (e) {
if (e instanceof ElementResolutionError && e.kind === "transient") {
return false; // keep waiting
}
throw e; // permanent → stop waiting immediately
}
});
Summary
ElementResolutionErroris defined insrc/element-resolver.tsand extends the nativeErrorclass- The error provides a
kindproperty with two values:"transient"for retryable failures and"permanent"for fatal selector errors - Transient errors indicate the element may appear after a delay (loading, hidden, stale), while permanent errors indicate malformed selectors or ambiguous matches
- The class is used throughout
src/driver/waits.tsandsrc/driver/locator.tsto drive intelligent polling and failure logic - Callers should use
instanceof ElementResolutionErrorand inspecterr.kindto decide between retrying and aborting
Frequently Asked Questions
How do I properly catch ElementResolutionError in ego-lite?
Import the class from src/element-resolver.ts and use an instanceof check within your catch block. This ensures you only handle the specific resolution error while allowing other unexpected errors to propagate naturally.
What causes a transient ElementResolutionError?
Transient errors occur when the target element exists in the page logic but is not currently resolvable due to timing. Common causes include network delays preventing DOM updates, CSS animations hiding the element, or stale references requiring a refresh cycle.
Why would a selector trigger a permanent ElementResolutionError?
Permanent errors indicate that the selector itself is the problem. This includes syntax errors in the selector string, queries that resolve to multiple elements when only one is expected, or attempts to reference attributes that do not exist on the matched element.
Which ego-lite files should I examine to understand resolution error handling?
Study src/element-resolver.ts for the class definition, src/driver/waits.ts for retry-loop implementations, src/driver/locator.ts for locator-specific handling, and src/element-resolver.test.mjs for unit tests demonstrating expected behavior patterns.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →