apify/crawlee · error · Error
Remote browser endpoint resolved to an empty string.
Error message
Remote browser endpoint resolved to an empty string.
What it means
RemoteBrowserPool accepts an endpoint either as a string or a function returning a string/object. When the endpoint is a function, it is awaited and the result validated; if it resolves to an empty string the pool cannot connect, so it throws with this message. It guards against silent misconfiguration producing empty endpoint values.
Source
Thrown at packages/browser-pool/src/remote-browser-pool.ts:78
readonly #onRelease: ((info: { endpoint: string; context?: Record<string, unknown> }) => unknown) | undefined;
readonly #log: CrawleeLogger;
constructor(
endpoint: RemoteBrowserEndpoint,
onRelease: ((info: { endpoint: string; context?: Record<string, unknown> }) => unknown) | undefined,
log: CrawleeLogger,
) {
this.#endpoint = endpoint;
this.#onRelease = onRelease;
this.#log = log;
}
async resolve(options?: { proxyUrl?: string }): Promise<{ url: string; token: number }> {
const resolved = typeof this.#endpoint === 'function' ? await this.#endpoint(options) : this.#endpoint;
let result: ResolvedRemoteEndpoint;
if (typeof resolved === 'string') {
if (!resolved) throw new Error('Remote browser endpoint resolved to an empty string.');
result = { url: resolved };
} else if (!resolved?.url) {
throw new Error("Remote browser endpoint() must return a URL string or an object with a non-empty 'url'.");
} else {
result = resolved;
}
const token = this.#nextToken++;
this.#sessions.set(token, { url: result.url, context: result.context, released: false });
return { url: result.url, token };
}
async release(token: number): Promise<void> {
const session = this.#sessions.get(token);
// Release at most once per session — guards a close()/teardown race (the `released` flag is set
// synchronously before the awaited onRelease, so releaseAll() can't double-fire an in-flight release).
if (!session || session.released) return;
session.released = true;View on GitHub (pinned to dbe57fb09c)
Solutions
- Fix the endpoint function to return a valid ws/http URL; check the source (env var, config, API) for the empty value.
- Add a default/fallback or fail fast at startup: throw early if the configured endpoint is empty.
- Log the resolved value before returning it from the endpoint function to catch empty resolutions during development.
Example fix
// before
new RemoteBrowserPool({ endpoint: async () => process.env.REMOTE_BROWSER_URL ?? '' });
// after
new RemoteBrowserPool({
endpoint: async () => {
const url = process.env.REMOTE_BROWSER_URL;
if (!url) throw new Error('REMOTE_BROWSER_URL is not set');
return url;
},
}); Defensive patterns
Strategy: validation
Validate before calling
const resolved = await endpointFn();
if (typeof resolved === 'string' && !resolved) {
throw new Error('Remote browser endpoint is empty; check env/config before pool init');
} Type guard
function isNonEmptyString(v: unknown): v is string {
return typeof v === 'string' && v.length > 0;
} Try / catch
try {
await remotePool.init();
} catch (err) {
if (err instanceof Error && err.message.includes('resolved to an empty string')) {
// re-read env/config or retry provisioning, then re-init
} throw err;
} Prevention
- Fail fast at startup if the endpoint env var/config is missing or empty.
- Have endpoint functions throw on unresolvable values instead of returning ''.
- Log resolved endpoints (redacted) in CI to catch empty provisioning early.
When it happens
Trigger: Providing a function endpoint to RemoteBrowserPool (or the pool config) that returns '' — e.g. an env var that is unset, an API returning an empty url field, or template interpolation of a missing value.
Common situations: REMOTE_BROWSER_URL environment variable missing/empty in CI or containers; a provisioning endpoint returning an empty body parsed to ''; race where the browser server hasn't published its URL yet.
Related errors
- Remote browser endpoint() must return a URL string or an obj
- ${crawlerName}: ${names.map((name) => `\`${name}\``).join(',
- Provided browserPlugin is not one of the plugins used by Bro
- Stagehand instance not found for browser
- Could not resolve StagehandController for page — is the brow
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/c00c94c09aca1710.
Report an issue: GitHub.