Provisioning Troubleshooting

How to read a ctrld provisioning failure, what each failure code means, and how to fix it.

🚧

Organizations Only

Mass provisioning is an Organization feature. This page covers failures from a provisioning code, RMM script, or MDM profile.

Overview

When a ctrld install fails to provision, it always reports the same fixed code, on every channel. This page shows you where to find that code, what each code means, and what to do next. Most codes you can fix yourself, without a support ticket.

Step 1: Find the failure code

Every provisioning failure logs one fixed line:

provisioning failed: stage=<stage> code=<CODE> (exit <N>)

Where you see it depends on how you deployed:

  • macOS MDM (.pkg): the line is in /var/log/install.log on the device, prefixed ctrld postinstall:.

    sudo grep 'ctrld postinstall:' /var/log/install.log
  • RMM script, /dl one-liner, or manual ctrld start: the line prints straight to the output of the command or script that ran the install.

The RMM script's own preflight checks (a bad MODE value, a bad CUSTOM_UID) and an invalid /dl intercept_mode parameter (HTTP 400) run before ctrld starts. None of them produce a stage=... code=... line. Instead, the script's or the API's own error text names the bad argument.

On every channel, ctrld also keeps a result file for Support: provision_result.json, next to the persisted ctrld.log. The default path is /etc/controld/provision_result.json on macOS and Linux. On Windows, it sits next to ctrld.exe. The file never contains the provisioning token.

Step 2: Run ctrld diag

Before you do anything else, run:

sudo ctrld diag

Add --json for a machine-readable version:

sudo ctrld diag --json

diag reports the client version, the MDM-managed preferences (macOS only), the last provisioning result, the service state, and whether the Control D API is reachable. It never requires a service to be installed, and it never prints the provisioning token — only whether one is present. It is safe to paste into a support ticket as-is.

Failure codes

CodeWhat it meansWhat to do
PROVISION_TOKEN_MALFORMEDThe provisioning code is not shaped like one: too short, too long, or it has stray whitespace.Copy the code again from the dashboard. Paste it with no extra spaces or line breaks.
CUSTOM_HOSTNAME_INVALIDThe custom hostname contains a character a hostname cannot use.Fix the hostname: letters, digits, hyphens, and dots only, 3–64 characters.
INTERCEPT_MODE_INVALIDThe intercept mode value is not one this channel accepts.Use a valid value for the channel. /dl script: dns or hard. MDM profile: standard or intercept-dns.
API_UNREACHABLEctrld did not reach the Control D API after several retries.Make sure that DNS, proxy, and firewall rules allow the device to reach api.controld.com. The service retries on its own once the network recovers.
API_REJECTEDThe API rejected the request outright (bad token or bad request).Make sure that the provisioning code and org settings in the dashboard are correct, then re-run the install.
API_DEVICE_INVALIDThe API reports this device's endpoint no longer exists.Re-provision the device with a current, active provisioning code.
TOKEN_INVALIDThe API does not recognize this provisioning code.Create or select an active provisioning code, then re-download the profile or script.
TOKEN_EXPIREDThe provisioning code passed its expiry date.Create or select an active provisioning code, then re-download the profile or script.
TOKEN_LIMIT_REACHEDThe provisioning code reached its device limit.Free a device slot, or create a new code, then re-download the profile or script.
TOKEN_DISABLEDThe provisioning code was invalidated.Create or select an active provisioning code, then re-download the profile or script.
LISTENER_BIND_FAILEDctrld did not bind any DNS listener address. Every fallback address was already taken.Free port 53 on the device, or make sure that the configured address exists on the device. sudo lsof -i :53 -nP shows what uses it.
LISTENER_CONFIGURED_ADDR_UNAVAILABLEThe listener address you configured cannot be bound, and ctrld will not fall back to another one.Make sure that the listed address exists on the device, and that nothing else uses it.
SERVICE_INSTALL_FAILEDThe OS refused to install the ctrld service.Make sure that no permission or MDM policy issue blocks new services, then contact support with your ctrld diag output.
SERVICE_START_FAILEDThe service installed but did not start.Contact support with your ctrld diag output.
SERVICE_SELFCHECK_FAILEDThe service started but failed its own health check, and rolled itself back.Contact support with your ctrld diag output.
UNCLASSIFIEDA failure that does not yet have its own code.Contact support with your ctrld diag output.
PROFILE_PREFS_MISSINGmacOS package install only. The MDM configuration profile with the provisioning token never reached the device before the package installed.Make sure that the profile is scoped to this device, then re-push the package.
SERVICE_RELOAD_FAILEDmacOS package upgrade only. The new package installed, but the active service did not reload.Run sudo launchctl load /Library/LaunchDaemons/ctrld.plist, or re-push the package.

Before you deploy

Before you roll out a provisioning code, make sure that the settings below are correct. This avoids the input-stage failures listed above.

Provisioning token

  • Length: 6–64 characters.
  • Current codes start with org-v1- (for example org-v1-EXAMPLE1234). Some older codes do not have this prefix. That is not a failure on its own.

Custom hostname

ctrld makes sure that the custom hostname is valid before it makes any network call. It uses a two-tier rule:

  • Letters, digits, and hyphens: kept exactly as typed.
  • Dots: ctrld accepts them, but the Control D server can fold or strip dots when it registers the device. The endpoint name in the dashboard can then differ slightly from what you requested.
  • Any other character (spaces, +, @, _, and so on): fails the install with CUSTOM_HOSTNAME_INVALID, on the channel where you typed the value.

Also: 3–64 characters, and a valid RFC1123 hostname shape (no leading or trailing hyphen, no empty label). Some setups depend on an exact hostname match downstream. If yours does, make sure that the endpoint name in the dashboard matches what you expect after the device enrolls.

Intercept mode

The accepted values depend on where you set intercept mode — these channels do not all share a vocabulary:

ChannelAccepted values
MDM configuration profile (InterceptMode key)standard, intercept-dns
RMM script one-liner (MODE argument)standard, intercept-dns
/dl install script or URL parameterdns, hard

Use the value set for the channel you deploy through. If you use a value from a different channel, ctrld reports INTERCEPT_MODE_INVALID.

Stale profiles and scripts

When you edit or invalidate a provisioning code, it does not change a profile or install script you already downloaded or deployed. Devices that already enrolled continue to work. Only new enrollments through the old code stop.

After you change a provisioning code:

  1. Re-download the configuration profile or install script.
  2. Re-push it to your fleet.

An MDM or RMM console that shows an old profile or script after a code change is stale, not broken. Re-download and re-push to pick up the change.


Did this page help you?