Skip to content

Doctor and repair

Terminal window
benchbar doctor # read only, exit 1 when something fails
benchbar repair --dry-run # show the plan, change nothing
benchbar repair # apply, with a confirmation prompt

Doctor checks the Homebrew formulae, the bench env, bench version, the socket.io module, the built assets that assets.json references, honcho, Procfile.lean, the runner, the launchd agent and its last exit code, the stop flag, the shell helpers, legacy agents, the MariaDB bind address and charset config, the PDF engine (wkhtmltopdf, and on v16 the Chromium frappe can use), a stray Homebrew Redis on 6379, Full Disk Access for crontab, the toolchain as the bench sees it (Node, yarn, the MariaDB server, pkg-config), honcho without pkg_resources, the fork safety variables, stale processes on the bench’s ports, the site ping, /etc/hosts, log sizes, CleanMyMac, and port clashes with other benches. Every warning and failure names its fix.

Repair runs only the flagged fixes, in dependency order. A broken env/ is moved to env.broken.<timestamp>, never deleted. The most common case, a cleanup tool that removed env/, node_modules and the built assets, is covered in Troubleshooting.

Reading the output

Each check prints one line, [OK], [WARN] or [FAIL], with its label and a message. A fix: line with the exact command follows every WARN and FAIL. benchbar doctor --json prints the same checks with their id, level, fix_command and action: the id is the heading of each check below, and the action is what repair would run. The format is in the JSON schema.

Doctor exits 1 when any check fails. Warnings alone exit 0. It never changes anything, never asks for a password and never reads the Keychain, so the app runs it on a timer.

Checks with a repair action are fixed by benchbar repair. The others name a command for you to run, because the change is a person’s call (for example which branch an app follows) or needs another app (Full Disk Access, CleanMyMac). Commands and flags are in the CLI reference.

System checks

The checks run in four groups, in this order: system, bench, service and site. benchbar service and adopt look only at the service group.

brew

The Homebrew formulae of the bench’s profile are installed: the Python, Node and MariaDB formulae, and redis. A missing one fails. The build formulae pkgconf and mariadb-connector-c (needed to build mysqlclient for frappe v16) are a warning when missing.

Fix: install Homebrew from https://brew.sh when it is missing; run 00-mac-system-deps.sh --profile <profile> from the checkout for missing formulae, or brew install pkgconf mariadb-connector-c for the build formulae.

python_leaves

The profile’s Python (for example python@3.11) exists, has the version the profile expects, and was installed on request, so brew autoremove cannot delete it.

Fix: brew install or brew reinstall the formula when it is missing or the wrong version. When it is only a dependency, repair marks it installed on request (brew tab --installed-on-request <formula>).

mariadb_bind

MariaDB listens on 127.0.0.1 only, or, when it is not running, the bind address drop-in frappe-mac-local-only.cnf exists. A server reachable from the network is a warning.

Fix: benchbar repair writes the drop-in into $(brew --prefix)/etc/my.cnf.d/ and restarts MariaDB.

mariadb_utf8

The utf8mb4 drop-in frappe.cnf in $(brew --prefix)/etc/my.cnf.d/ is current, and my.cnf includes that folder. Frappe needs utf8mb4 server wide. A drop-in written by someone else that sets utf8mb4 is accepted and left alone. Doctor reads the files only; it never logs in to MariaDB.

Fix: benchbar repair writes the drop-in and the !includedir line.

pdf_engine

wkhtmltopdf is the patched Qt build, the one Frappe needs for PDFs, and no unpatched Homebrew wkhtmltopdf comes first on PATH. On a v16 profile it also says whether the Chromium that Print Formats set to “chrome” use has been downloaded.

Fix: benchbar repair installs the official patched package (with sudo). A shadowing Homebrew build: brew uninstall wkhtmltopdf. The v16 Chromium: cd <bench> && bench setup-chrome.

redis_6379

Nothing listens on port 6379. The bench runs its own Redis on its port block, so a Homebrew Redis on 6379 is unused.

Fix: brew services stop redis, only if nothing else needs it.

cleanmymac

CleanMyMac is not installed in /Applications or ~/Applications. Its cleanup can delete env/, node_modules and public/dist, which is the most common cause of a bench that suddenly stops working.

Fix: in CleanMyMac, add the bench folder to the Ignore List before running any cleanup.

full_disk_access

crontab is readable. Without Full Disk Access for the Terminal, bench init and bench setup backups fail with “Operation not permitted”. Not checked when BenchBar runs doctor, since the permission belongs to the Terminal that runs bench.

Fix: System Settings > Privacy & Security > Full Disk Access: add Terminal (or the app that runs benchbar), then open a new window.

Bench checks

env_python

env/bin/python exists, runs, and is the Python version the profile expects.

Fix: benchbar repair rebuilds the env; the old one is moved to env.broken.<timestamp>.

bench_version

bench version works in the bench folder. The message also says whether pipx or uv owns bench.

Fix: benchbar repair rebuilds the env.

toolchain_node

The node the bench’s processes see (launchd’s PATH, not your shell’s) has the major version the profile expects. nvm’s node is only on your shell’s PATH, so the bench does not see it.

Fix: brew install <node formula>; the bench’s PATH puts it first.

toolchain_yarn

yarn is on the bench’s PATH. bench build needs it.

Fix: npm install -g yarn with the bench’s npm.

mariadb_version

A MariaDB server listens on 3306 and its version is in the range the profile accepts: 10.6 to 10.11 for v15, 10.6 to 11.8 for v16. Outside the range is a warning, as it is in Frappe.

Fix: brew services start <mariadb formula> when nothing listens; brew install <mariadb formula> for a version outside the range.

toolchain_pkgconfig

pkg-config is on the bench’s PATH and finds mariadb-connector-c. mysqlclient for frappe v16 needs both.

Fix: brew install pkgconf mariadb-connector-c.

socketio

apps/frappe/node_modules/socket.io exists. Without it socketio fails with “Cannot find module ‘socket.io’”.

Fix: benchbar repair runs bench setup requirements --node.

assets

sites/assets/assets.json exists and every dist file it references is there. Missing files make the site load without styling.

Fix: benchbar repair runs bench build.

apps_txt

Every app in sites/apps.txt has a folder in apps/, and every git app in apps/ is listed. A listed app without a folder fails, because every bench command then fails to import it. An unlisted git app is a warning: usually a get-app that did not finish.

Fix: benchbar app add <app> for a missing app. For an unlisted one, move the folder aside, then benchbar app add <its git URL>. Repair has no action here: changing code is your call.

app_branch_policy

Each git app is on the branch config/apps.tsv names for the profile.

Fix: git fetch and git checkout the policy branch in the app, only if you meant to follow the policy. Repair has no action here.

lock_parse

The bench’s benchbar.toml lockfile, when one is set, exists and parses. See the team lockfile.

Fix: correct the file by hand, or write it again with benchbar lock write. A lockfile path that does not exist yet: benchbar lock write --lock <path>.

lock_drift

The bench matches its lockfile: the same apps, repos, branches and pinned commits. Drift is a warning.

Fix: benchbar lock apply (benchbar lock check lists the differences).

logs

bench.log, worker.log and worker.error.log are under 50 MB each.

Fix: benchbar repair moves large logs aside.

Service checks

port_block

Shown only in the plan of install, adopt or service when the bench’s ports are about to move to another block (because another bench uses them, or --port-offset asked for it). Doctor never shows it.

Fix: part of the plan: benchbar service --port-offset <n> moves the ports with bench set-config -g.

honcho

honcho, which runs the Procfile, is found on PATH, in the pipx venv of frappe-bench, or in the bench’s env/bin.

Fix: benchbar repair installs it into the bench env. adopt never installs into env; install it with pipx install honcho first.

honcho_setuptools

honcho imports cleanly. honcho 1.x imports pkg_resources, which Python 3.12 and later only have with setuptools installed.

Fix: benchbar repair installs setuptools into honcho’s own venv only.

procfile

Procfile.lean exists, was written by benchbar, and matches its template and the bench’s settings (for example the scheduler choice).

Fix: benchbar repair writes it again; the old copy goes to the backups.

runner

The runner script benchbar-run.sh is current, and no old frappe-mac-run.sh is left in the bench.

Fix: benchbar repair writes it again. A running bench picks the new runner up on its next start.

agent

The launchd agent plist is current and loaded, and its last exit code is not an error.

Fix: benchbar repair writes and loads it. A non zero last exit code: benchbar logs shows why.

fork_safety

The agent passes OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES and NO_PROXY=* to every process. Without them macOS kills forked workers.

Fix: benchbar repair writes the agent again.

scheduler

Reports whether the scheduler runs in Procfile.lean. It is a choice, so this check never warns.

Fix: none needed. benchbar service --with-schedule turns it on, --without-schedule off.

stop_flag

No stop flag, or a stop on purpose (benchdown). A flag of crash (three crashes in ten minutes) or broken (honcho or env was missing) means auto restart is paused.

Fix: benchbar logs, fix the cause, then benchup. For broken: benchbar repair, then benchup.

helpers

The # >>> benchbar >>> block in ~/.zshrc with benchup and the other helpers is present and current. Old helper blocks from earlier setups are reported.

Fix: benchbar repair writes the block. Remove an old block by hand.

~/.local/bin/benchbar and ~/.local/bin/frappe-mac are links to this checkout, so both names work from any folder.

Fix: benchbar repair writes the links. A file that is not a link is left alone: move it aside and link again.

legacy_agents

No per process LaunchAgents (one each for web, worker, socketio and so on) and no agent from frappe-mac 0.2.

Fix: benchbar repair boots them out and moves the plists to ~/Library/LaunchAgents-disabled/<timestamp>/.

hosts

/etc/hosts maps the site to 127.0.0.1.

Fix: benchbar repair adds the line (with sudo), or printf '127.0.0.1 <site>\n' | sudo tee -a /etc/hosts.

port_clash

No other bench benchbar knows uses this bench’s web, socketio or Redis ports, running or not. Two benches set up with the same ports cannot run at the same time.

Fix: benchbar service --port-offset <n> --bench-dir <bench> moves this bench to the next free block (or stop the other bench). See Port blocks.

orphans

No stale process holds the bench’s ports while the agent and honcho are not running. A killed bench start can leave Redis, socketio or gunicorn behind, and the agent then cannot start.

Fix: benchbar down (or benchbar restart) stops only this bench’s leftovers.

Site checks

ping

http://<site>:<port>/api/method/ping returns 200. A stopped bench is fine; processes that run but do not answer fail.

Fix: benchbar logs shows why; benchup starts a stopped bench.