{"record":{"id":"bb71ca9528a616d9","repo":"phacility/phabricator","slug":"this-host-already-has-a-registered-private-key","errorCode":null,"errorMessage":"This host already has a registered private key (\"%s\"). Remove this key before registering the host, or use --force to overwrite it.","messagePattern":"This host already has a registered private key \\(\"(.+?)\"\\)\\. Remove this key before registering the host, or use --force to overwrite it\\.","errorType":"console","errorClass":"PhutilArgumentUsageException","httpStatus":null,"severity":"warning","filePath":"src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php","lineNumber":119,"sourceCode":"          $phd_user));\n    }\n\n    $stored_public_path = AlmanacKeys::getKeyPath('device.pub');\n    $stored_private_path = AlmanacKeys::getKeyPath('device.key');\n    $stored_device_path = AlmanacKeys::getKeyPath('device.id');\n\n    if (!$args->getArg('force')) {\n      if (Filesystem::pathExists($stored_public_path)) {\n        throw new PhutilArgumentUsageException(\n          pht(\n            'This host already has a registered public key (\"%s\"). '.\n            'Remove this key before registering the host, or use '.\n            '--force to overwrite it.',\n            Filesystem::readablePath($stored_public_path)));\n      }\n\n      if (Filesystem::pathExists($stored_private_path)) {\n        throw new PhutilArgumentUsageException(\n          pht(\n            'This host already has a registered private key (\"%s\"). '.\n            'Remove this key before registering the host, or use '.\n            '--force to overwrite it.',\n            Filesystem::readablePath($stored_private_path)));\n      }\n    }\n\n    // NOTE: We're writing the private key here so we can change permissions\n    // on it without causing weird side effects to the file specified with\n    // the `--private-key` flag. The file needs to have restrictive permissions\n    // before `ssh-keygen` will willingly operate on it.\n    $tmp_private = new TempFile();\n    Filesystem::changePermissions($tmp_private, 0600);\n    execx('chown %s %s', $phd_user, $tmp_private);\n    Filesystem::writeFile($tmp_private, $raw_private_key);\n\n    list($raw_public_key) = execx('ssh-keygen -y -f %s', $tmp_private);","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php#L101-L137","documentation":"Companion check to the public-key guard in `bin/almanac register`: without --force, an existing device private key file at AlmanacKeys::getKeyPath('device.key') blocks registration. Because the workflow rewrites this file (to a temp copy with restrictive permissions for ssh-keygen, then installs the final copy), silently clobbering an in-use private key would break the host's Almanac identity.","triggerScenarios":"Re-running register after a previous success; an earlier run that wrote device.key then failed later (e.g. at the trust check); key files present from a restored backup while --force is omitted.","commonSituations":"Provisioning automation that is not idempotent; recovering from a failed first registration attempt without cleaning the key directory; rotating device keys without remembering the --force flag.","solutions":["Pass --force when you deliberately want to install a new key pair.","Otherwise leave the existing identity in place and remove the register step from the run.","For a clean slate, delete device.pub, device.key and device.id from the Almanac keys directory shown in the message, then register again."],"exampleFix":"# before\n$ bin/almanac register --device web-001 --private-key ./new_device.key\nUsage Exception: This host already has a registered private key (\"../almanac/keys/device.key\"). ...\n\n# after (key rotation)\n$ bin/almanac register --force --device web-001 --private-key ./new_device.key","handlingStrategy":"validation","validationCode":"$priv = AlmanacKeys::getKeyPath('device.key');\n$pub  = AlmanacKeys::getKeyPath('device.pub');\nif (Filesystem::pathExists($priv) || Filesystem::pathExists($pub)) {\n  // decide: skip, or explicit rotation with --force\n  if (!$rotate) { return; }\n}","typeGuard":null,"tryCatchPattern":"# idempotent wrapper: 'already registered' (either key) is OK\nif ! out=$(bin/almanac register \"$@\" 2>&1); then\n  echo \"$out\" | grep -q 'already has a registered' && exit 0\n  echo \"$out\" >&2; exit 1\nfi","preventionTips":["Check both device.key and device.pub before re-running register.","Model key rotation as its own script that always passes --force and re-trusts the new key.","Log which identity a host currently has so re-provisioning decisions are explicit."],"tags":["phabricator","almanac","cli","register","idempotency","ssh-key"],"backgroundTag":"resource-already-exists","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}