microsoft/playwright · error · Error
Unknown method: ${method}
Error message
Unknown method: ${method} What it means
Thrown by the CLI daemon's socket message handler when the inbound `method` is neither `'stop'` nor `'run'`. The daemon protocol recognizes exactly two methods; any other value falls into the `else` branch and is rejected. The error is caught and sent back over the socket as the response error, not rethrown.
Source
Thrown at packages/playwright-core/src/tools/cli-daemon/daemon.ts:99
const abortController = new AbortController();
connection.onclose = () => abortController.abort();
connection.onmessage = async message => {
const { id, method, params } = message;
try {
if (method === 'stop') {
await deleteSessionFile(clientInfo, sessionConfig);
const sendAck = async () => connection.send({ id, result: 'ok' }).catch(() => {});
if (options?.exitOnClose)
gracefullyProcessExitDoNotHang(0, () => sendAck());
else
await sendAck();
} else if (method === 'run') {
const { toolName, toolParams } = parseCliCommand(params.args);
toolParams._meta = { cwd: params.cwd, raw: params.raw || params.json, json: !!params.json };
const response = await backend.callTool(toolName, toolParams, abortController.signal);
await connection.send({ id, result: formatResult(response) });
} else {
throw new Error(`Unknown method: ${method}`);
}
} catch (e) {
const error = process.env.PWDEBUGIMPL ? (e as Error).stack || (e as Error).message : (e as Error).message;
connection.send({ id, error }).catch(() => {});
}
};
});
decorateServer(server);
browserContext.on('close', () => Promise.resolve().then(async () => {
await deleteSessionFile(clientInfo, sessionConfig);
if (options?.exitOnClose)
gracefullyProcessExitDoNotHang(0);
}));
await new Promise<void>((resolve, reject) => {
server.on('error', reject);
server.listen(socketPath, () => resolve());View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Send only `method: "run"` (with `params.args`/`params.cwd`) or `method: "stop"`.
- Verify the CLI client and daemon are the same Playwright version (a newer method is not supported by an older daemon).
- Inspect the exact `method` string in the error to spot typos or undefined values caused by a malformed payload.
Example fix
// before
connection.send({ id: 1, method: 'list', params: {} });
// after
connection.send({ id: 1, method: 'run', params: { args: { _: ['screenshot'], target: 'ref' }, cwd: process.cwd() } }); Defensive patterns
Strategy: validation
Validate before calling
const KNOWN_METHODS = new Set(['run', 'stop']);
function buildFrame(id: number, method: string, params: any) {
if (!KNOWN_METHODS.has(method))
throw new TypeError(`Unsupported daemon method: ${method}`);
return { id, method, params };
} Type guard
type DaemonMethod = 'run' | 'stop';
function isDaemonMethod(m: string): m is DaemonMethod {
return m === 'run' || m === 'stop';
} Prevention
- Pin the CLI client and daemon to the same Playwright version.
- Send only 'run' or 'stop'; gate outbound frames with a known-methods set.
- When building a custom socket client, model the protocol as a literal-union type.
When it happens
Trigger: A client (CLI client, test harness, or custom script) sends a JSON message whose `method` field is anything other than `"stop"` or `"run"` (e.g. `"ping"`, `"list"`, a typo like `"runn"`, or an undefined field due to a malformed payload).
Common situations: Version skew between the CLI client and daemon (client uses a method added in a newer version); a hand-rolled socket client sending the wrong frame shape; a test that sends raw JSON without going through the SocketConnection helper.
Related errors
- --data must be in "mime/type=value" format, got: ${entry}
- Command is required
- ${path}: expected channel ${names.toString()}
- Cannot find command to respond: ${id}
- Cannot find object to "${method}": ${guid}
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/2c23553ccd422c1b.
Report an issue: GitHub.