{"record":{"id":"50616c8eef711fd7","repo":"phacility/phabricator","slug":"buildkite-request-to-target-s-had-the-wrong-aut","errorCode":null,"errorMessage":"Buildkite request to target \"%s\" had the wrong authentication token. The Buildkite pipeline and Harbormaster build step must be configured with the same token.","messagePattern":"Buildkite request to target \"(.+?)\" had the wrong authentication token\\. The Buildkite pipeline and Harbormaster build step must be configured with the same token\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/harbormaster/controller/HarbormasterBuildkiteHookController.php","lineNumber":70,"sourceCode":"          'Harbormaster build target \"%s\" does not exist.',\n          $target_phid));\n    }\n\n    $step = $target->getBuildStep();\n    $impl = $step->getStepImplementation();\n    if (!($impl instanceof HarbormasterBuildkiteBuildStepImplementation)) {\n      throw new Exception(\n        pht(\n          'Harbormaster build target \"%s\" is not a Buildkite build step. '.\n          'Only Buildkite steps may be updated via the Buildkite hook.',\n          $target_phid));\n    }\n\n    $webhook_token = $impl->getSetting('webhook.token');\n    $request_token = $request->getHTTPHeader('X-Buildkite-Token');\n\n    if (!phutil_hashes_are_identical($webhook_token, $request_token)) {\n      throw new Exception(\n        pht(\n          'Buildkite request to target \"%s\" had the wrong authentication '.\n          'token. The Buildkite pipeline and Harbormaster build step must '.\n          'be configured with the same token.',\n          $target_phid));\n    }\n\n    $state = idx($build, 'state');\n    switch ($state) {\n      case 'passed':\n        $message_type = HarbormasterMessageType::MESSAGE_PASS;\n        break;\n      default:\n        $message_type = HarbormasterMessageType::MESSAGE_FAIL;\n        break;\n    }\n\n    $api_method = 'harbormaster.sendmessage';","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/harbormaster/controller/HarbormasterBuildkiteHookController.php#L52-L88","documentation":"Authentication failure for the Buildkite webhook: the X-Buildkite-Token header sent with the delivery is not identical (compared in constant time via phutil_hashes_are_identical) to the 'webhook.token' setting stored on the Buildkite build step. The hook deliberately fails closed so a third party who learns the hook URL cannot forge build.finished events.","triggerScenarios":"The Buildkite pipeline's webhook notification header/token differs from (or omits) the token saved in the Harbormaster step settings; the token was regenerated in Harbormaster but not updated in Buildkite (or vice versa); trailing whitespace/newline introduced when pasting the token; no token configured on the step at all (null never equals the header).","commonSituations":"Initial setup where only one side got the token; rotating tokens during a security review and forgetting one side; copying hook URLs between pipelines that use different tokens.","solutions":["Copy the exact webhook.token from the Harbormaster Buildkite step into the Buildkite pipeline's webhook settings (X-Buildkite-Token header), with no extra whitespace.","If the token may have been pasted with whitespace, set it again cleanly on both sides.","After updating, re-test with a fresh Buildkite build (old deliveries keep the old header).","Never leave the step's webhook.token empty; the check will always fail."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before enabling the hook in Buildkite, verify both sides carry the same token:\n$step_token = $impl->getSetting('webhook.token');\nassert(strlen($step_token) > 0); // empty token can never authenticate\n// then set the identical value as the X-Buildkite-Token header in Buildkite","typeGuard":null,"tryCatchPattern":"try {\n  handleBuildkiteDelivery($request);\n} catch (Exception $e) {\n  if (preg_match('/wrong authentication token/', $e->getMessage())) {\n    // config issue, not transient: alert, do not retry\n  }\n  throw $e;\n}","preventionTips":["Store the webhook token in a secret manager and inject it into both Buildkite and the Harbormaster step from one source.","After any token rotation, update both ends and send a test delivery before resuming real builds.","Paste tokens with visible whitespace stripped; re-set the setting if a paste may have carried a newline."],"tags":["harbormaster","buildkite","webhook","authentication","token-mismatch"],"backgroundTag":"webhook-token-mismatch","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}