Files
vercel__next.js/test/development/lockfile/lockfile.test.ts
Jimmy Lai cb0d88f6e3 Improve existing dev server error message to suggest using it (#92317)
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
### What?

Improves the error message shown when a user tries to start `next dev`
while another dev server is already running in the same directory.

### Why?

Previously, the error message only suggested killing the existing
process (`Run kill <pid> to stop it.`). This wasn't the best advice —
often the user just wants to access the already-running dev server
rather than kill it and start a new one.

### How?

Updated the error message in `packages/next/src/build/lockfile.ts` to
present both options:

1. Access the existing server at its URL
2. Kill the process if they want to start a new one

**Before:**
```
✖ Another next dev server is already running.

- Local:        http://localhost:3000
- PID:          61479
- Dir:          /path/to/project
- Log:          .next/dev/logs/next-development.log

Run kill 61479 to stop it.
```

**After:**
```
✖ Another next dev server is already running.

- Local:        http://localhost:3000
- PID:          61479
- Dir:          /path/to/project
- Log:          .next/dev/logs/next-development.log

You can access the existing server at http://localhost:3000,
or run kill 61479 to stop it and start a new one.
```

Updated the lockfile test regex to match the new message format.
<!-- CURSOR_AGENT_PR_BODY_END -->

[Slack
Thread](https://vercel.slack.com/archives/C046HAU4H7F/p1775173304387809?thread_ts=1775173304.387809&cid=C046HAU4H7F)

<div><a
href="https://cursor.com/agents/bc-0bb3085b-1fd1-56c3-8617-cd8a32d8c376"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-0bb3085b-1fd1-56c3-8617-cd8a32d8c376"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-04-03 16:33:13 -07:00

72 lines
2.4 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
import execa from 'execa'
import fs from 'fs'
import path from 'path'
import stripAnsi from 'strip-ansi'
describe('lockfile', () => {
const { next, isTurbopack, isRspack } = nextTestSetup({
files: __dirname,
})
it('only allows a single instance of `next dev` to run at a time', async () => {
const browser = await next.browser('/')
expect(await browser.elementByCss('p').text()).toBe('Page')
// Verify lockfile was created with server info inside it
// With isolatedDevBuild (default), distDir is .next/dev
const distDir = path.join(next.testDir, '.next', 'dev')
const lockfilePath = path.join(distDir, 'lock')
expect(fs.existsSync(lockfilePath)).toBe(true)
// Read server info from the lockfile itself
const serverInfo = JSON.parse(fs.readFileSync(lockfilePath, 'utf-8'))
expect(serverInfo).toMatchObject({
pid: expect.any(Number),
port: expect.any(Number),
hostname: expect.any(String),
appUrl: expect.any(String),
startedAt: expect.any(Number),
})
// Try to start another dev server - should fail with helpful error
const { stdout, stderr, exitCode } = await execa(
'pnpm',
[
'next',
'dev',
...(isRspack ? [] : [isTurbopack ? '--turbopack' : '--webpack']),
],
{
cwd: next.testDir,
env: next.env as NodeJS.ProcessEnv,
reject: false,
}
)
const output = stripAnsi(stdout + stderr)
// Match the whole error message pattern with fuzzy matching for dynamic parts
// The kill command varies by platform: `kill <pid>` on Unix, `taskkill /PID <pid> /F` on Windows
const killPattern =
process.platform === 'win32'
? 'or run taskkill /PID \\d+ /F to stop it and start a new one\\.'
: 'or run kill \\d+ to stop it and start a new one\\.'
const errorPattern = new RegExp(
'Another next dev server is already running\\.\\s*' +
'- Local:\\s+http://[^\\s]+\\s+' +
'- PID:\\s+\\d+\\s+' +
'- Dir:\\s+[^\\s]+\\s+' +
'- Log:\\s+\\.next/dev/logs/next-development\\.log\\s+' +
'You can access the existing server at http://[^\\s]+,\\s+' +
killPattern
)
expect(output).toMatch(errorPattern)
expect(exitCode).toBe(1)
// Make sure the other instance of `next dev` didn't mess anything up
await browser.refresh()
expect(await browser.elementByCss('p').text()).toBe('Page')
})
})