phacility/phabricator · error · PhutilArgumentUsageException
Unable to change ownership of an identity file to daemon use
Error message
Unable to change ownership of an identity file to daemon user "%s". Run this command as %s or root.
What it means
Usage exception from `bin/almanac register`: exec_manual('chown <phd.user> <tmpfile>') returned a non-zero exit code, meaning the current user cannot change ownership of the identity temp file to the daemon user. The workflow then writes device.pub/device.key/device.id with daemon ownership, so it aborts and tells you to run as the daemon user or root.
Source
Thrown at src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php:96
if (!Filesystem::pathExists($private_key_path)) {
throw new PhutilArgumentUsageException(
pht('No private key exists at path "%s"!', $private_key_path));
}
$raw_private_key = Filesystem::readFile($private_key_path);
$phd_user = PhabricatorEnv::getEnvConfig('phd.user');
if (!$phd_user) {
throw new PhutilArgumentUsageException(
pht(
'Config option "phd.user" is not set. You must set this option '.
'so the private key can be stored with the correct permissions.'));
}
$tmp = new TempFile();
list($err) = exec_manual('chown %s %s', $phd_user, $tmp);
if ($err) {
throw new PhutilArgumentUsageException(
pht(
'Unable to change ownership of an identity file to daemon user '.
'"%s". Run this command as %s or root.',
$phd_user,
$phd_user));
}
$stored_public_path = AlmanacKeys::getKeyPath('device.pub');
$stored_private_path = AlmanacKeys::getKeyPath('device.key');
$stored_device_path = AlmanacKeys::getKeyPath('device.id');
if (!$args->getArg('force')) {
if (Filesystem::pathExists($stored_public_path)) {
throw new PhutilArgumentUsageException(
pht(
'This host already has a registered public key ("%s"). '.
'Remove this key before registering the host, or use '.
'--force to overwrite it.',View on GitHub (pinned to 5720a38cfe)
Solutions
- Rerun as root: sudo bin/almanac register ... (or as the phd.user account itself).
- Confirm phd.user spells an existing local account; fix with bin/config set phd.user <correct-user> if not.
- In restricted containers, run registration in an init/entrypoint step that has CAP_CHOWN, or pre-place the key files with correct ownership and skip re-registration.
Example fix
# before $ bin/almanac register --device web-001 --private-key ./device.key Usage Exception: Unable to change ownership of an identity file to daemon user "phd-daemon". ... # after $ sudo bin/almanac register --device web-001 --private-key ./device.key
Defensive patterns
Strategy: try-catch
Validate before calling
// Guard: registration needs root or the phd user to chown identity files
$u = posix_getpwuid(posix_geteuid());
$phd_user = (string)PhabricatorEnv::getEnvConfig('phd.user');
if ($u['name'] !== 'root' && $u['name'] !== $phd_user) {
throw new RuntimeException('Run register as root or '.$phd_user);
} Try / catch
# shell wrapper case "$(id -un)" in root|$PHD_USER) exec bin/almanac register "$@" ;; *) echo "re-run as root or $PHD_USER" >&2; exit 1 ;; esac
Prevention
- Standardize on `sudo bin/almanac register` in all runbooks.
- Verify phd.user exists on the host before registration (getent passwd).
- In containers, ensure the entrypoint holds CAP_CHOWN or pre-stage key files.
When it happens
Trigger: Running bin/almanac register as an ordinary admin shell user; running under sudo but with a phd.user whose name is misspelled so chown fails; containerized environments where chown is restricted by capability settings.
Common situations: Operators running register from their own account out of habit; hardened/immutable images without CAP_CHOWN; the phd.user account renamed after config was written.
Related errors
- Specify a device with --device.
- Specify a private key with --private-key.
- Config option "phd.user" is not set. You must set this optio
- This host already has a registered public key ("%s"). Remove
- This host already has a registered private key ("%s"). Remov
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/7abb856691f91575.
Report an issue: GitHub.