{"record":{"id":"f1d30032a25ba589","repo":"cypress-io/cypress","slug":"unable-to-automerge-with-the-config-file","errorCode":null,"errorMessage":"Unable to automerge with the config file","messagePattern":"Unable to automerge with the config file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/config/src/ast-utils/addToCypressConfig.ts","lineNumber":54,"sourceCode":" *\n * becomes:\n *    export default {\n *      projectId: '...',\n *      ...createConfigFn()\n *    }\n */\nexport async function addToCypressConfig (filePath: string, code: string, toAdd: t.ObjectProperty) {\n  try {\n    const ast = parse(code, {\n      parser: require('recast/parsers/typescript'),\n    })\n\n    traverse(ast, addToCypressConfigPlugin(toAdd).visitor)\n\n    return print(ast).code\n  } catch (e: any) {\n    debug(`Error adding properties to %s: %s`, filePath, e.stack)\n    throw new Error(`Unable to automerge with the config file`)\n  }\n}\n\ninterface AddProjectIdToCypressConfigOptions {\n  filePath: string\n  projectId: string\n}\n\nexport async function addProjectIdToCypressConfig (options: AddProjectIdToCypressConfigOptions) {\n  try {\n    let result = await fs.readFile(options.filePath, 'utf8')\n    const toPrint = await addToCypressConfig(options.filePath, result, t.objectProperty(\n      t.identifier('projectId'),\n      t.identifier(options.projectId),\n    ))\n\n    await fs.writeFile(options.filePath, maybeFormatWithPrettier(toPrint, options.filePath))\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/cypress-io/cypress/blob/0d85fdc91230885bca0a91df278312800a48b727/packages/config/src/ast-utils/addToCypressConfig.ts#L36-L72","documentation":"Thrown by addToCypressConfig when the recast/babel-based AST parse-and-print pipeline fails for the user's cypress.config file. The function parses the file with recast's typescript parser, runs an AST visitor (addToCypressConfigPlugin) that injects an ObjectProperty, then prints back. Any failure — malformed TypeScript, unsupported syntax, recast bug, visitor assertion — is caught, logged via debug with the full stack, and rethrown as this generic message so the user sees a clean error rather than a babel internals dump.","triggerScenarios":"Cypress attempts to automerge a property (commonly projectId after recording, or a setupNodeEvents change) into a cypress.config.ts/js that contains syntax recast's typescript parser cannot round-trip: decorators with metadata, satisfies operator on very old recast, experimental syntax without the right plugin, or a hand-corrupted file.","commonSituations":"First-time recording setup when Cypress tries to write projectId, very new TS syntax not yet supported by the pinned recast, custom config files using macros or non-standard plugins, or a config file that already has a parse error from manual editing.","solutions":["Open cypress.config.ts and fix any existing syntax or TypeScript errors first (`npx tsc --noEmit cypress.config.ts`).","Add the property (e.g. projectId) manually instead of relying on automerge.","If using experimental/decorator syntax, check the pinned recast supports it; simplify the config to a plain object export.","Re-run with DEBUG=cypress:config to see the recast stack trace (logged before the throw)."],"exampleFix":"// before: cypress.config.ts contains invalid syntax\nexport default defineConfig({ e2e: { setupNodeEvents(on) { /* unclosed } })\n// after\nexport default defineConfig({\n  e2e: {\n    setupNodeEvents(on) {},\n    projectId: 'abc123', // added manually instead of automerge\n  },\n})","handlingStrategy":"try-catch","validationCode":"import { readFileSync } from 'fs'\nimport { parse } from '@babel/parser'\n\nfunction isParsableConfig (filePath: string): boolean {\n  try {\n    parse(readFileSync(filePath, 'utf8'), { sourceType: 'module', plugins: ['typescript'] })\n    return true\n  } catch { return false }\n}","typeGuard":"function isRecastCompatible (code: string): boolean {\n  try {\n    const recast = require('recast')\n    recast.parse(code, { parser: require('recast/parsers/typescript') })\n    return true\n  } catch { return false }\n}","tryCatchPattern":"try {\n  await addProjectIdToCypressConfig({ filePath, projectId })\n} catch (e) {\n  if (/Unable to automerge/.test(e.message)) {\n    // Fall back to manual edit instructions for the user\n    informUserManualProjectId(projectId)\n    return\n  }\n  throw e\n}","preventionTips":["Keep cypress.config.ts to plain, stable TypeScript the pinned recast supports.","Run `tsc --noEmit cypress.config.ts` before invoking automerge.","Avoid experimental syntax in the config file."],"tags":["config","ast","recast","automerge","typescript"],"backgroundTag":null,"analyzedSha":"0d85fdc91230885bca0a91df278312800a48b727","analyzedAt":"2026-08-12T16:24:28.056Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}