cypress-io/cypress · error
Unable to automerge with the config file
Error message
Unable to automerge with the config file
What it means
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.
Source
Thrown at packages/config/src/ast-utils/addToCypressConfig.ts:54
*
* becomes:
* export default {
* projectId: '...',
* ...createConfigFn()
* }
*/
export async function addToCypressConfig (filePath: string, code: string, toAdd: t.ObjectProperty) {
try {
const ast = parse(code, {
parser: require('recast/parsers/typescript'),
})
traverse(ast, addToCypressConfigPlugin(toAdd).visitor)
return print(ast).code
} catch (e: any) {
debug(`Error adding properties to %s: %s`, filePath, e.stack)
throw new Error(`Unable to automerge with the config file`)
}
}
interface AddProjectIdToCypressConfigOptions {
filePath: string
projectId: string
}
export async function addProjectIdToCypressConfig (options: AddProjectIdToCypressConfigOptions) {
try {
let result = await fs.readFile(options.filePath, 'utf8')
const toPrint = await addToCypressConfig(options.filePath, result, t.objectProperty(
t.identifier('projectId'),
t.identifier(options.projectId),
))
await fs.writeFile(options.filePath, maybeFormatWithPrettier(toPrint, options.filePath))
View on GitHub (pinned to 0d85fdc912)
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).
Example fix
// before: cypress.config.ts contains invalid syntax
export default defineConfig({ e2e: { setupNodeEvents(on) { /* unclosed } })
// after
export default defineConfig({
e2e: {
setupNodeEvents(on) {},
projectId: 'abc123', // added manually instead of automerge
},
}) Defensive patterns
Strategy: try-catch
Validate before calling
import { readFileSync } from 'fs'
import { parse } from '@babel/parser'
function isParsableConfig (filePath: string): boolean {
try {
parse(readFileSync(filePath, 'utf8'), { sourceType: 'module', plugins: ['typescript'] })
return true
} catch { return false }
} Type guard
function isRecastCompatible (code: string): boolean {
try {
const recast = require('recast')
recast.parse(code, { parser: require('recast/parsers/typescript') })
return true
} catch { return false }
} Try / catch
try {
await addProjectIdToCypressConfig({ filePath, projectId })
} catch (e) {
if (/Unable to automerge/.test(e.message)) {
// Fall back to manual edit instructions for the user
informUserManualProjectId(projectId)
return
}
throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- No tsconfig.json found. ts-loader needs a tsconfig.json file
- Could not read '${path}'.
- Failed to parse "${this.path}" as JSON AST Object. ${printPa
- Incompatible versions detected, @cypress/grep 3.0.0+ require
- Missing vite dev server port.
AI-assisted analysis of cypress-io/cypress@0d85fdc912 (2026-08-12).
Data as JSON: /api/errors/f1d30032a25ba589.
Report an issue: GitHub.