apify/crawlee · error

Compilation result is not a function!

Error message

Compilation result is not a function!

What it means

compileScript evaluates a user script string with vm.runInNewContext and expects the evaluation to yield a function (the interception/scrolling routine). If the compiled value is not a function, this defensive error is thrown since the result could never be invoked downstream.

Source

Thrown at packages/playwright-crawler/src/internals/utils/playwright-utils.ts:363

 * still execute in the main process via prototype manipulation. Therefore you
 * should only use this function to execute sanitized or safe code.
 *
 * Custom context may also be provided using the `context` parameter. To improve security,
 * make sure to only pass the really necessary objects to the context. Preferably making
 * secured copies beforehand.
 */
export function compileScript(scriptString: string, context: Dictionary = Object.create(null)): CompiledScriptFunction {
    const funcString = `async ({ page, request }) => {${scriptString}}`;

    let func;
    try {
        func = vm.runInNewContext(funcString, context); // "Secure" the context by removing prototypes, unless custom context is provided.
    } catch (err) {
        getLog().exception(err as Error, 'Cannot compile script!');
        throw err;
    }

    if (typeof func !== 'function') throw new Error('Compilation result is not a function!'); // This should not happen...

    return func;
}

export interface InfiniteScrollOptions {
    /**
     * How many seconds to scroll for. If 0, will scroll until bottom of page.
     * @default 0
     */
    timeoutSecs?: number;

    /**
     * How many pixels to scroll down. If 0, will scroll until bottom of page.
     * @default 0
     */
    maxScrollHeight?: number;

    /**

View on GitHub (pinned to dbe57fb09c)

Solutions

  1. Ensure the script string is a function expression, e.g. 'async ({ request, continue, respond, abort }) => { ... }' rather than a bare statement or IIFE call.
  2. Log the compiled value locally (evaluating the same string) to confirm it evaluates to typeof 'function'.
  3. Check that the script does not rely on globals removed by the sandboxed context.

Example fix

// before
const script = "window.scrollTo(0, document.body.scrollHeight)";
// after
const script = "async ({ page }) => { await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); }";
Defensive patterns

Strategy: validation

Validate before calling

// validate before compiling
const compiled = new Function(`return (${script})`)();
if (typeof compiled !== 'function') throw new Error('Script must be a function expression');

Type guard

function isCompiledFunction(v: unknown): v is (...args: unknown[]) => unknown {
    return typeof v === 'function';
}

Try / catch

try {
    const fn = compileScript(script);
} catch (err) {
    if ((err as Error).message === 'Compilation result is not a function!') {
        throw new Error(`Script must evaluate to a function, got: ${script.slice(0, 80)}`);
    }
    throw err;
}

Prevention

When it happens

Trigger: Passing a script string to compileScript (used by interceptRequestCompiler for request interception and infiniteScrollCompiler) that evaluates to a non-function value, e.g. an expression like 'window.scrollTo(0, document.body.scrollHeight)' (a call, not a definition) instead of an arrow/function expression.

Common situations: Writing an interception script as an immediately-invoked statement rather than a function; typo causing undefined; script compiled in a context where referenced helpers are stripped, yielding undefined.

Related errors


AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30). Data as JSON: /api/errors/47830b5b72b7c6b3. Report an issue: GitHub.