microsoft/playwright-mcp · error · Error

Config type not found in config.d.ts

Error message

Config type not found in config.d.ts

What it means

update-readme.js embeds the user-facing Config type into README.md by reading `config.d.ts` (the published type definitions) and regex-extracting the `export type Config = { ... };` declaration. If that regex fails to match — because the declaration moved, was renamed, or its formatting changed — the script throws rather than generating an empty config section. It is a fragile-by-design check that surfaces drift between the script's expectations and the generated .d.ts bundle.

Source

Thrown at update-readme.js:225

  const startMarker = `<!--- Options generated by ${path.basename(__filename)} -->`;
  const endMarker = `<!--- End of options generated section -->`;
  return updateSection(content, startMarker, endMarker, table);
}

/**
 * @param {string} content
 * @returns {Promise<string>}
 */
async function updateConfig(content) {
  console.log('Updating config schema from config.d.ts...');
  const configPath = path.join(__dirname, 'config.d.ts');
  const configContent = await fs.promises.readFile(configPath, 'utf-8');

  // Extract the Config type definition
  const configTypeMatch = configContent.match(/export type Config = (\{[\s\S]*?\n\});/);
  if (!configTypeMatch)
    throw new Error('Config type not found in config.d.ts');

  const configType = configTypeMatch[1]; // Use capture group to get just the object definition

  const startMarker = `<!--- Config generated by ${path.basename(__filename)} -->`;
  const endMarker = `<!--- End of config generated section -->`;
  return updateSection(content, startMarker, endMarker, [
    '```typescript',
    configType,
    '```',
  ]);
}

async function updateReadme() {
  const readmePath = path.join(__dirname, 'README.md');
  const readmeContent = await fs.promises.readFile(readmePath, 'utf-8');
  const withTools = await updateTools(readmeContent);
  const withOptions = await updateOptions(withTools);
  const withConfig = await updateConfig(withOptions);

View on GitHub (pinned to 16cf228d7b)

Solutions

  1. Regenerate the type definitions first (`npm run build` or whatever produces config.d.ts in utils/), then rerun `node utils/update-readme.js`.
  2. Inspect config.d.ts and confirm it still contains `export type Config = {` with the closing `};` on its own line; if the declaration shape changed (interface, intersection, union), update the regex in updateConfig (update-readme.js:~222) to match the new form.
  3. If Config was legitimately restructured, either restore a self-contained object literal type in the emitted d.ts or extend the extraction logic to handle the new syntax before rerunning the script.

Example fix

// before (config.d.ts) — closing brace not on its own line breaks the regex
export type Config = { browser: { launchOptions?: LaunchOptions } };

// after
export type Config = {
  browser: {
    launchOptions?: LaunchOptions;
  };
};
Defensive patterns

Strategy: validation

Validate before calling

// Check the d.ts still exposes the expected declaration shape before generating:
import fs from 'fs';

const dts = fs.readFileSync('utils/config.d.ts', 'utf-8');
if (!/export type Config = (\{[\s\S]*?\n\});/.test(dts)) {
  console.error('config.d.ts no longer contains a matchable `export type Config = { ... };` block — regenerate types or update the extraction regex.');
  process.exit(1);
}

Type guard

function hasExtractableConfigType(dtsContent) {
  return /export type Config = (\{[\s\S]*?\n\});/.test(dtsContent);
}

Try / catch

try {
  content = await updateConfig(content);
} catch (e) {
  if (/Config type not found in config\.d\.ts/.test(e.message)) {
    console.warn('Skipping config section: config.d.ts shape changed.');
    return content; // keep the previously generated config section
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `node utils/update-readme.js` when config.d.ts no longer contains a literal `export type Config = {` ... `};` block — e.g. the type was renamed, extracted into an imported interface, made to extend another type, or the file wasn't regenerated after source changes so config.d.ts is missing or stale. The non-greedy regex `/(\{[\s\S]*?\n\});/` also fails if the closing brace is not at the start of a line (e.g. minified or differently formatted output).

Common situations: Refactoring src/config.ts so Config becomes an interface or a union; regenerating config.d.ts with a newer TypeScript compiler that formats the emitted declaration differently (e.g. `export type Config = { ... } & SharedOptions;`); running the script on a fresh clone before `npm run build` has produced config.d.ts; declaration emit bundling (api-extractor/dts-bundle) reordering or annotating the block with comments that break the `\n});` anchor.

Related errors


AI-assisted analysis of microsoft/playwright-mcp@16cf228d7b (2026-08-27). Data as JSON: /api/errors/8aff7a7e2684ef4d. Report an issue: GitHub.