feat(sdk): give Docker-not-running error an actionable next step (#20280)

## Summary

The current Docker-not-running message is unhelpful in two ways:

1. It doesn't tell users **how** to start Docker
2. "try again" is meaningless because a first-time user doesn't yet know
the command they just ran (they got here from `create-twenty-app`, not
from typing `yarn twenty server start` themselves)

**Before:**
```
Docker is not running. Please start Docker and try again.
```

**After (macOS example):**
```
Docker is not running.

Start Docker:
  Run: open -a Docker
  (or launch Docker Desktop from Applications)

Then retry:
  yarn twenty server start

Don't have Docker? Install from https://docs.docker.com/get-docker/
```

The platform-specific line is detected via `process.platform`:
- `darwin` → `open -a Docker` + Docker Desktop fallback
- `linux` → `sudo systemctl start docker` + Docker Desktop fallback
- `win32` → "Launch Docker Desktop from the Start menu"
- other → link to install docs

The retry command is computed at the call site so it preserves the
user's actual flags — `yarn twenty server start --test`, `yarn twenty
server upgrade 2.2.0 --test`, etc.

## Why

This came out of shadowing a first-time app developer who hit this error
during `npx create-twenty-app`. They were stuck — the CLI told them to
"try again" but they had only learned two commands so far
(`create-twenty-app` and `yarn dev`), neither of which was the right
one. Improving the message turns the error into a teaching moment.

## Test plan
- [x] `npx nx typecheck twenty-sdk` passes
- [x] `npx nx lint twenty-sdk` passes
- [x] Manually verified rendered output for both `server start` and
`server upgrade` flows on macOS
- [ ] Verify message renders correctly on Linux/Windows in practice

## Possible follow-ups (out of scope)

- Auto-launch Docker Desktop on macOS if installed (changes user state —
separate PR)
- Make the multi-line CLI error printer style only the first line in
red, so guidance reads as default text rather than red

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Félix Malfait
2026-05-05 15:24:12 +02:00
committed by GitHub
parent f9a24072b7
commit e50adaff2d
3 changed files with 42 additions and 2 deletions
@@ -9,6 +9,7 @@ import {
DEFAULT_PORT,
DEFAULT_TEST_PORT,
getContainerPort,
getDockerNotRunningMessage,
IMAGE,
isContainerRunning,
TEST_CONTAINER_NAME,
@@ -148,11 +149,15 @@ const innerServerStart = async (
}
if (!checkDockerRunning()) {
const retryCommand = isTest
? 'yarn twenty server start --test'
: 'yarn twenty server start';
return {
success: false,
error: {
code: SERVER_ERROR_CODES.DOCKER_NOT_RUNNING,
message: 'Docker is not running. Please start Docker and try again.',
message: getDockerNotRunningMessage(retryCommand),
},
};
}
@@ -6,6 +6,7 @@ import {
containerExists,
getContainerDigest,
getContainerPort,
getDockerNotRunningMessage,
getImageDigest,
getImageForVersion,
TEST_CONTAINER_NAME,
@@ -30,11 +31,19 @@ const innerServerUpgrade = async (
const { version = 'latest', test: isTest, onProgress } = options;
if (!checkDockerRunning()) {
const retryCommand = [
'yarn twenty server upgrade',
version !== 'latest' ? version : null,
isTest ? '--test' : null,
]
.filter(Boolean)
.join(' ');
return {
success: false,
error: {
code: SERVER_ERROR_CODES.DOCKER_NOT_RUNNING,
message: 'Docker is not running. Please start Docker and try again.',
message: getDockerNotRunningMessage(retryCommand),
},
};
}
@@ -103,3 +103,29 @@ export const checkDockerRunning = (): boolean => {
return false;
}
};
const getDockerStartInstruction = (): string => {
switch (process.platform) {
case 'darwin':
return ' Run: open -a Docker\n (or launch Docker Desktop from Applications)';
case 'linux':
return ' Run: sudo systemctl start docker\n (or launch Docker Desktop if installed)';
case 'win32':
return ' Launch Docker Desktop from the Start menu';
default:
return ' See https://docs.docker.com/engine/install/ for installation';
}
};
export const getDockerNotRunningMessage = (retryCommand: string): string =>
[
'Docker is not running.',
'',
'Start Docker:',
getDockerStartInstruction(),
'',
'Then retry:',
` ${retryCommand}`,
'',
"Don't have Docker? Install from https://docs.docker.com/get-docker/",
].join('\n');