Skip to content

brew services: use package-provided service file when no run command - #23413

Closed
Yuxin-Qiao wants to merge 1 commit into
Homebrew:mainfrom
Yuxin-Qiao:services-bundled-service-file
Closed

brew services: use package-provided service file when no run command#23413
Yuxin-Qiao wants to merge 1 commit into
Homebrew:mainfrom
Yuxin-Qiao:services-bundled-service-file

Conversation

@Yuxin-Qiao

@Yuxin-Qiao Yuxin-Qiao commented Aug 3, 2026

Copy link
Copy Markdown

  • Have you followed our Contributing guidelines?
  • Have you checked for other open Pull Requests for the same change?
  • Have you explained what your changes do? Performance claims (e.g. "this is faster") must include Hyperfine benchmarks.
  • Have you explained why you'd like these changes included, not just what they do?
  • For bug fixes, have you given step-by-step brew commands to reproduce the bug?
  • Have you written new tests (excluding integration tests)? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) locally?

What this does

brew services start/restart again uses the service file installed by the formula (the package-provided plist/systemd unit) when the formula's service do block does not define a run command.

PR #23312 changed install_service_file to always regenerate the service file from the service do block via service_contents. Formulas that ship their own service file only define name (without run), so the regenerated plist had an empty ProgramArguments and launchctl bootstrap failed with exit code 5 (Input/output error). Examples in homebrew-core: dbus, xinit.

This restores the documented contract from the Formula Cookbook: if name is defined without run, Homebrew makes no attempt to change the package-provided service file. It matches the logic already used by FormulaInstaller#install_service, which only writes a generated plist when formula.service.command? is true.

The per-service environment variable overrides from #23312 still apply whenever Homebrew generates the service file (i.e. when a run command is defined).

Why

PR #23312 unintentionally dropped support for package-provided service files, breaking brew services start for formulae that ship their own plist/systemd unit (e.g. dbus, xinit in homebrew-core). The generated file is invalid for such formulae because the service do block contains only name, so launchctl bootstrap rejects it with exit code 5.

Step-by-step reproduction

brew install zhyu/tap/roused
brew services start roused

Before this fix:

Bootstrap failed: 5: Input/output error
Error: Failure while executing; `/bin/launchctl bootstrap gui/501 /Users/.../io.github.zhyu.roused.plist` exited with 5.

How it was verified

  • brew tests --only=services --no-parallel: 119 examples, 0 failures
  • brew style on the changed files: no offenses
  • brew typecheck: no errors
  • New unit test covers the fallback to the installed service file

  • I did not use AI/LLM to create this PR, or I disclosed the tool/model below and reviewed its output; I did not attribute commits to AI and will answer maintainer questions and review comments myself without AI/LLM.

AI (Claude Code via Codex) was used to analyze the issue, implement the fix, and prepare this PR. The change was reviewed, typechecked with Sorbet, linted with RuboCop, and verified with the services test suite locally before submission.


Fixes #23408

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for your pull request. This has been closed because it appears to use an incomplete or outdated pull request template.

Please edit this pull request to fill in the current pull request template. This workflow will reopen this pull request automatically once the template is complete. Do not open a new pull request for this.

@github-actions github-actions Bot closed this Aug 3, 2026
@github-actions github-actions Bot reopened this Aug 3, 2026
Restore the pre-Homebrew#23312 behaviour where `brew services start`/restart
copied the service file installed by the formula into the keg instead of
regenerating it from the `service do` block. Formulas that ship their
own plist or systemd unit only define `name` (without `run`), so
regenerating the file produces an invalid one with an empty
ProgramArguments/ExecStart, and `launchctl bootstrap` fails with exit
code 5.

Only regenerate the service file when the formula defines a run
command; otherwise fall back to the installed file. This matches the
documented contract in the Formula Cookbook and the logic already used
by FormulaInstaller#install_service.

Fixes Homebrew#23408
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

brew services no long use the package-provided service file after #23312

1 participant