Jenkins macOS Agent drops offline: do not reinstall first. This week, capture the controller and node evidence, then check scheduling, transport, Java, macOS session persistence, and the Xcode toolchain in that order; repair the isolated fault, and rebuild or isolate the node only after repeated failures or environment drift.
This guide is for:
- DevOps engineers maintaining Jenkins and remote Mac build nodes.
- Apple-platform developers running automated Xcode builds, tests, or signing jobs.
- CI platform owners defining recovery evidence before adding a long-running macOS node.
Start with a recovery timeline, not a reinstall
A disconnected-looking node can represent several different failures. Jenkins may have marked the node offline while the Mac itself remains reachable. The node may be online but unable to accept a job. A job may be queued because its label or executor requirements do not match. The workspace may be unusable even though the Agent process is healthy.
Use this order during the first response:
- First observation: record the controller time, node status, queue reason, last successful build, and the exact error text.
- First evidence pass: save the controller log, node log, and remote process state before restarting anything.
- Connection layer: verify the launch method actually configured for the node.
- Runtime layer: verify the Java process, Agent parameters, credentials, and Secret.
- macOS layer: verify the owning user, logout behavior, reboot behavior, and automatic launch mechanism.
- Build layer: verify remote root, workspace permissions, Xcode selection, tests, and signing.
- This week’s action: run the recovery checklist below and classify the node as repaired, isolated, or ready for rebuild.
The actionable rule: an occasional process failure is a repair case. Repeated transport loss, environment drift, or lost signing state is a node lifecycle problem.
The opening conflict: SSH works, Jenkins says offline
Suppose the Mac accepts SSH, but the Jenkins node page shows the Agent as disconnected. Do not conclude that Jenkins is broken or that the Mac is healthy. System SSH and Jenkins Agent transport are different paths.
Save these items before making changes:
- The exact timestamp of the first offline event.
- The controller-side disconnect or handshake message.
- The node log from the last successful connection.
- The result of
psor an equivalent process inspection on the Mac. - The configured launch method: controller-initiated SSH, inbound connection, or WebSocket-based transport.
- The current node label, executor setting, remote root, and offline reason.
- The Java executable path and the user owning the Agent process.
The Jenkins node management documentation distinguishes nodes, executors, and Agent connections. Use those definitions when separating a disconnected node from a scheduling problem.
02Separate scheduling failure from a dead Jenkins Agent
Start at the controller. Open the node details and inspect whether Jenkins reports a lost connection, an administrative offline state, or an Agent that is technically connected. Then inspect the queue item. A queue reason such as an unmatched label points to scheduling, not necessarily to a network failure.
Check the following:
- Does the job request the same label assigned to the macOS node?
- Is the node temporarily marked offline by an administrator or automation?
- Does the node have an executor available?
- Does the job require a tool or capability that the node does not advertise?
- Does the remote root directory exist and belong to the Agent user?
- Did the last successful job use the same pipeline path and credentials?
A simple shell step can produce a false positive. It may run successfully while Xcode cannot locate the selected developer directory, test devices, provisioning assets, or a writable workspace. Treat “Agent online” as a transport result, not a production readiness result.
Three evidence locations
Controller evidence shows what Jenkins believes happened. Look for connection closure, authentication failure, channel termination, queue explanations, or an explicit offline action.
Node evidence shows whether the Mac received a launch request and whether the Java process remained alive. Capture standard output and standard error from the configured launch mechanism. Avoid replacing the launch command before saving its failure output.
Mac evidence shows whether the operating system terminated the process, whether the user session changed, and whether the workspace or developer tools became inaccessible. Check process state, file ownership, disk availability, and the logs belonging to the actual launch mechanism.
This three-way comparison prevents a common mistake: restarting the Mac because the controller reported “offline” when the real cause is a label mismatch or a manually applied offline flag.
03Check the configured connection path
The correct diagnostic path depends on the node’s Launch Method. Do not use the controller’s SSH service, the Mac’s Remote Login service, and Jenkins Agent transport as interchangeable components.
Controller-initiated SSH
For an SSH-launched Agent, verify:
- The controller resolves the Mac hostname to the expected address.
- The configured account is valid.
- The key or credential has not been replaced or revoked.
- Host verification still matches the intended Mac.
- The Mac’s Remote Login service is enabled for that account.
- The remote Java path and working directory are available to that user.
Apple describes how to enable and manage Remote Login on macOS. That documentation covers the Mac-side SSH service. It does not prove that Jenkins can start and maintain its Agent process after login.
If a manual SSH session succeeds, repeat the test with the same account, working directory, environment assumptions, and non-interactive behavior used by Jenkins. An interactive shell may load configuration files or permissions that a service launch does not receive.
Inbound or WebSocket-based connection
For an inbound connection, verify that the Agent process can reach the controller address from the Mac. Check DNS, proxy rules, firewall policy, certificate validation, and any controller address change. If WebSocket transport is configured, test that path specifically. A successful system SSH test is not evidence for an inbound Jenkins channel.
The Jenkins Agent usage guide explains the relationship between the controller and Agent process. The Jenkins services and ports reference covers the services that may be exposed and the security implications of those paths. Use the documented transport instead of opening broad access as a quick fix.
What counts as a repaired connection
A single successful reconnect is weak evidence. Mark the transport layer as repaired only when:
- The Agent completes a stable handshake.
- The controller continues to receive heartbeats.
- The node stays connected after the original process is left alone.
- A controller restart does not permanently strand the node.
- The selected launch method reconnects without manually copying a new Secret.
If the Secret changed, update the deployment from the controller’s current node configuration. Keep hostnames, usernames, keys, and Secrets as placeholders in runbooks. Never paste live credentials into scripts, tickets, or build logs.
04Verify Java and the Jenkins Agent process
After the transport path is known to work, inspect the process. On the Mac, confirm whether the Agent process exists, which user owns it, which Java executable it uses, and whether it exited. Capture the exit code and standard error from the service or terminal that launched it.
Common patterns include:
agent.jaror another Agent artifact does not match the controller’s current expectation.- The Java path works interactively but is not visible to the service context.
- A startup argument was removed or quoted incorrectly.
- The node Secret no longer matches.
- The process exits immediately because of a runtime compatibility problem.
- macOS terminates the process or the owning session ends.
Do not hard-code a Java version in a generic troubleshooting article. Jenkins support changes with the Jenkins release line and Java runtime. Check the current Jenkins Java support policy against the controller version and the installed runtime before changing Java.
A useful process check is narrow and observable:
ps aux | grep -i '[j]ava'
This only tells you whether a matching process is visible. It does not prove that the process belongs to the intended node or has a working Jenkins channel. Confirm the command arguments, user, working directory, and recent output separately.
When the process is absent, repair the launch command or runtime first. Reinstalling the entire node can erase evidence and create a second problem: a new workspace with different permissions, tools, or signing state.
05Make macOS session persistence explicit
Manual SSH success does not prove unattended operation. A process started inside an interactive session may stop after logout, a VNC disconnect, a user switch, or a reboot. The key question is not “can I start the Agent?” It is “does the intended launch mechanism start it under the correct user without a desktop session?”
Inspect:
- The account that owns the Agent.
- The account’s home directory and workspace permissions.
- The Java and Agent paths available outside an interactive shell.
- The deployed automatic startup mechanism.
- Its current status and logs.
- Whether the launch context can access required credentials and signing resources.
If the deployment uses launchd, inspect the configuration actually installed on the target macOS version. Do not paste a generic plist into production without validating its labels, paths, ownership, environment, and lifecycle behavior. launchd behavior can vary with the user-level or system-level context. Treat community templates as starting points, not official guarantees.
Use a controlled sequence:
- Stop the Agent through its real service mechanism.
- Start it through that same mechanism.
- Confirm the process owner and Jenkins connection.
- Log out of the owning user session.
- Confirm whether the Agent remains connected.
- Reboot the Mac.
- Wait for unattended startup and record whether reconnection is automatic.
- Review logs for duplicate processes or repeated restart loops.
A node that requires a developer to log in and launch Java is not a reliable long-running CI node. It may still be suitable for occasional interactive work, but it should not be treated as production infrastructure.
06Treat an online node as unready until Xcode passes
An online Jenkins Agent can still leave Xcode CI jobs queued or fail after checkout. The build layer needs its own evidence.
Check the remote root and workspace first:
- The directory exists on the Mac.
- The Agent user can create and remove files there.
- The disk has sufficient free space for checkout, derived data, archives, and test output.
- The workspace is not owned by a different account.
- Concurrent jobs do not reuse unsafe temporary paths.
- The node label matches the job’s platform and tool requirements.
Then inspect the Xcode context under the Agent user. xcode-select -p can show the selected developer directory, while xcodebuild -version can identify the active Xcode command-line context. Apple documents Xcode command-line tool settings and Command Line Tools installation. Use the current target system to confirm the installed components rather than assuming a path from another Mac.
Check three job classes separately:
Compile acceptance
- Checkout succeeds.
- Dependencies resolve.
- The intended scheme and configuration build.
- Artifacts are written to a known, writable location.
Test acceptance
- The test destination exists.
- Simulator or device dependencies are available.
- Test results are exported and retained.
- A failed test is distinguishable from an Agent disconnect.
Apple’s Xcode test execution documentation describes how test results are produced and interpreted.
Signing acceptance
- The Agent user can access the required certificates and profiles.
- Keychain access does not depend on an interactive desktop unlock.
- The bundle identifier, entitlements, and export settings match the release job.
- The archive and signed output are retained for inspection.
Apple’s signed code archive guidance is the reference for the signing and archive stage. A successful echo command is not a valid substitute for a signing test.
Use a repair-or-rebuild decision
Use the following checklist after collecting evidence. Tick each item only when you have a log entry or a repeatable command result.
- [ ] The controller log identifies the first failure time and connection message.
- [ ] The node log and remote process state agree about whether the Agent was running.
- [ ] The configured Launch Method has been tested through its own transport path.
- [ ] DNS, proxy, firewall, certificate, credential, and Secret changes have been ruled out.
- [ ] The Java runtime satisfies the current Jenkins support policy.
- [ ] The Agent runs under the intended macOS account, not only an interactive test account.
- [ ] The Agent survives logout and a full unattended reboot.
- [ ] The remote root is writable and has enough operational disk space.
- [ ] The node label, executor setting, and job requirements allow scheduling.
- [ ] A compile job passes under the Agent user.
- [ ] A test job produces inspectable results.
- [ ] A signing job reaches the archive or export stage with the expected credentials.
- [ ] A short network interruption does not leave a stale online state.
- [ ] A controller restart does not require manual Agent intervention.
- [ ] The recovery result, elapsed time, and human actions are recorded.
Choose in-place repair when one failure is isolated, the node retains its expected toolchain, and unattended recovery passes.
Choose isolation and rebuild when the Agent repeatedly loses its connection, the startup context is unclear, permissions drift between jobs, or signing resources disappear after reboot.
Choose an additional independent remote Mac when one node is both a production builder and the only recovery path. Separation limits the blast radius of upgrades, disk cleanup, signing changes, and long-running jobs.
A Mac mini server can be a reasonable alternative when you need direct physical access and predictable ownership. It is less attractive when the machine must remain online at another location and you do not want to manage hardware replacement, power recovery, network access, and remote console operations yourself. Compare those operational costs with the Mac rental options and pricing before committing to a permanent architecture.
08FAQ: Jenkins macOS Agent recovery
The following answers target the failure patterns that are often misclassified during incident response.
The key test is not whether the node icon turns green once. It is whether the node reconnects after the controller restarts, the Mac reboots, the user logs out, and a short network interruption occurs. Then run separate compile, test, and signing jobs. Keep the evidence with the node record so the next incident starts from facts rather than assumptions.
A remote Mac with full administrative control can also simplify recovery when the existing build host cannot be independently restarted or has an unstable session context. If you decide that the current node is no longer worth repairing, review remote Mac hosting options and compare them with rebuilding your own hardware.
If you need a disposable or long-running macOS CI environment, VpsMesh can provide a real remote Mac with SSH, VNC, or web-console access and full root permissions. That is most useful when you need to test a clean Jenkins node, replace a drifting builder, or add an isolated Xcode CI capacity without purchasing another Mac. Review the available remote Mac order options after completing the evidence-based decision above.