microsoft/playwright · error · Error

Either path or content property must be present

Error message

Either path or content property must be present

What it means

Thrown at the end of evaluationScript() when the `fun` object form has neither `content` nor `path`. The helper accepts a function, a string, or an object { path?, content? }; reaching the final throw means none of those branches matched a usable source.

Source

Thrown at packages/playwright-core/src/client/clientHelper.ts:51

export async function evaluationScript(fun: Function | string | { path?: string, content?: string }, arg?: any, addSourceUrl: boolean = true): Promise<string> {
  if (typeof fun === 'function') {
    const source = fun.toString();
    const argString = Object.is(arg, undefined) ? 'undefined' : JSON.stringify(arg);
    return `(${source})(${argString})`;
  }
  if (arg !== undefined)
    throw new Error('Cannot evaluate a string with arguments');
  if (isString(fun))
    return fun;
  if (fun.content !== undefined)
    return fun.content;
  if (fun.path !== undefined) {
    let source = await fs.promises.readFile(fun.path, 'utf8');
    if (addSourceUrl)
      source = addSourceUrlToScript(source, fun.path);
    return source;
  }
  throw new Error('Either path or content property must be present');
}

export async function initScriptSourceWithExposedFunctions(fun: Function, arg: any, expose: (name: string, callback: Function) => Promise<void>): Promise<string> {
  const exposePromises: Promise<void>[] = [];
  const serialized = serializeAsCallArgument(arg, value => {
    if (typeof value === 'function') {
      const name = kFunctionBindingPrefix + createGuid();
      exposePromises.push(expose(name, value));
      return { fn: name };
    }
    return { fallThrough: value };
  });
  await Promise.all(exposePromises);
  // Bindings backing the functions are registered through their own init scripts
  // that are guaranteed to run first, so the controller is available here.
  return `(${fun.toString()})(globalThis['${kBindingsControllerProperty}'].parseInitScriptArg(${JSON.stringify(serialized)}))`;
}

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Provide content: `evaluationScript({ content: 'window.x=1' })`.
  2. Or provide path: `evaluationScript({ path: './init.js' })`.
  3. Double-check key names are exactly 'path' or 'content'.

Example fix

// before
await evaluationScript({ contents: 'window.x=1' });
// after
await evaluationScript({ content: 'window.x=1' });
Defensive patterns

Strategy: validation

Validate before calling

function isScriptObject(v: any): boolean {
  return typeof v === 'object' && v !== null
    && (typeof v.content === 'string' || typeof v.path === 'string');
}
if (!isFunctionScript(s) && typeof s !== 'string' && !isScriptObject(s))
  throw new Error("Provide { path } or { content }.");

Type guard

function hasPathOrContent(v: any): v is { path?: string; content?: string } {
  return typeof v === 'object' && v !== null
    && (typeof v.path === 'string' || typeof v.content === 'string');
}

Prevention

When it happens

Trigger: Passing `evaluationScript({})`, or an object with typos like `{ contents: '...' }` or `{ filename: '...' }`. Both fun.content and fun.path are undefined, so execution falls through.

Common situations: Building the options object dynamically and omitting both keys; misreading the API and using `file`/`source` instead of `path`/`content`.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/c3e010312013ea61. Report an issue: GitHub.