puppeteer/puppeteer · error · Error

Element cannot be filled out.

Error message

Element cannot be filled out.

What it means

Thrown by Locator.fill() when the target element is classified as an 'unknown' input type that Puppeteer cannot fill. The locator first categorizes the element (checkable-input, select, contenteditable, typeable-input, other-input, unknown); only 'unknown' throws, meaning the element is neither a recognizable form control nor editable content.

Source

Thrown at packages/puppeteer-core/src/api/locators/locators.ts:611

                          (input as HTMLInputElement).value = '';
                          (input as HTMLInputElement).value = currentValue;
                        }
                        return valString.substring(currentValue.length);
                      }, value),
                    ).pipe(
                      mergeMap(textToType => {
                        if (!textToType) {
                          return of(undefined);
                        }
                        return from(handle.type(textToType));
                      }),
                    );
                  }
                  return fillDirectly();
                case 'other-input':
                  return fillDirectly();
                case 'unknown':
                  throw new Error(`Element cannot be filled out.`);
              }
            }),
          )
          .pipe(
            catchError(err => {
              void handle.dispose().catch(error => {
                this.#logger?.(DEBUG_PREFIXES.error)?.(error);
              });
              throw err;
            }),
          );
      }),
      this.operators.retryAndRaceWithSignalAndTimer(signal, cause),
    );
  }

  #hover<ElementType extends Element>(
    this: Locator<ElementType>,

View on GitHub (pinned to d484e21c17)

Solutions

  1. Point the locator at a real fillable element: input, textarea, select, or a contentEditable node.
  2. If you must set text on a non-input, use `locator.evaluate((el, v) => { el.textContent = v; }, value)` instead.
  3. For custom elements, expose a value or make them contentEditable so the locator recognizes them.

Example fix

// before
await page.locator('div.greeting').fill('hello');
// after
await page.locator('input#name').fill('hello');
Defensive patterns

Strategy: validation

Validate before calling

const tag = await el.evaluate(node => node.tagName.toLowerCase());
if (!['input', 'textarea', 'select'].includes(tag) &&
    !(await el.evaluate(n => (n as HTMLElement).isContentEditable))) {
  throw new Error('element is not fillable');
}
await page.locator(sel).fill('text');

Type guard

async function isFillable(el: ElementHandle): Promise<boolean> {
  return el.evaluate(node => {
    const n = node as HTMLElement;
    return ['INPUT', 'TEXTAREA', 'SELECT'].includes(n.tagName) || n.isContentEditable;
  });
}

Try / catch

try {
  await page.locator(sel).fill('text');
} catch (e) {
  if (e instanceof Error && /cannot be filled/.test(e.message)) {
    await page.locator(sel).evaluate((el, v) => { (el as HTMLElement).textContent = v; }, 'text');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `page.locator('div#label').fill('text')` on a non-input, non-editable element such as a plain div, span, or image. Also triggered on custom elements that don't expose a value or contentEditable interface.

Common situations: Selector matches a wrapper/container instead of the actual input; shadow-DOM custom element that Puppeteer can't introspect; wrong locator target after a DOM refactor.

Related errors


AI-assisted analysis of puppeteer/puppeteer@d484e21c17 (2026-08-12). Data as JSON: /api/errors/8f54721fa18a2293. Report an issue: GitHub.