{"record":{"id":"8a4dfb55aa9ca617","repo":"oven-sh/bun","slug":"azure-auth-failed-response-status","errorCode":null,"errorMessage":"Azure auth failed: ${response.status}","messagePattern":"Azure auth failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/machine.mjs","lineNumber":1140,"sourceCode":" * @property {number} [memoryGb]\n * @property {number} [diskSizeGb]\n * @property {boolean} [preemptible]\n * @property {boolean} [detached]\n * @property {Record<string, unknown>} [tags]\n * @property {boolean} [bootstrap]\n * @property {boolean} [ci]\n * @property {boolean} [rdp]\n * @property {string} [userData]\n * @property {SshKey[]} sshKeys\n */\n\nasync function getAzureToken(tenantId, clientId, clientSecret) {\n  const response = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n    body: `grant_type=client_credentials&client_id=${clientId}&client_secret=${encodeURIComponent(clientSecret)}&scope=https://management.azure.com/.default`,\n  });\n  if (!response.ok) throw new Error(`Azure auth failed: ${response.status}`);\n  const data = await response.json();\n  return data.access_token;\n}\n\n/**\n * Build a Windows image using Packer (Azure only).\n * Packer handles VM creation, bootstrap, sysprep, and gallery capture via WinRM.\n * This eliminates all the Azure Run Command issues (output truncation, x64 emulation,\n * PATH not refreshing, stderr false positives, quote escaping).\n */\nasync function buildWindowsImageWithPacker({ os, arch, release, command, ci, agentPath, bootstrapPath }) {\n  const { getSecret } = await import(\"./utils.mjs\");\n\n  // Determine Packer template\n  const templateName = arch === \"aarch64\" ? \"windows-arm64\" : \"windows-x64\";\n  const templateDir = resolve(import.meta.dirname, \"packer\");\n  const templateFile = join(templateDir, `${templateName}.pkr.hcl`);\n","sourceCodeStart":1122,"sourceCodeEnd":1158,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/scripts/machine.mjs#L1122-L1158","documentation":"getAzureToken() POSTs an OAuth2 client-credentials grant to https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token; any non-2xx throws with just the HTTP status. Common statuses: 400 invalid_client (bad/expired secret, wrong client id), 401 (wrong tenant), 403 (conditional access blocking).","triggerScenarios":"AZURE_CLIENT_SECRET expired or rotated and the Buildkite secret is stale; wrong AZURE_TENANT_ID or AZURE_CLIENT_ID; one of the secret values is undefined so the URL/body is malformed; network egress blocked to login.microsoftonline.com.","commonSituations":"Service principal secret past its expiry in CI; getSecret() returning empty because the Buildkite secret wasn't created; tenant GUID copy-paste error.","solutions":["Verify all four AZURE_* secrets resolve non-empty before the call","Test the principal directly: `az login --service-principal -u <clientId> -p <secret> --tenant <tenantId>`","Rotate the client secret and update the Buildkite secret if it expired","Map the status: 400 invalid_client = bad secret/id, 401 = wrong tenant, 403 = conditional access"],"exampleFix":"// before\nconst token = await getAzureToken(tenantId, clientId, clientSecret);\n\n// after\nfor (const [k, v] of Object.entries({ tenantId, clientId, clientSecret })) {\n  if (!v) throw new Error(`missing Azure credential: ${k}`);\n}\nconst token = await getAzureToken(tenantId, clientId, clientSecret);","handlingStrategy":"validation","validationCode":"for (const [k, v] of Object.entries({ AZURE_TENANT_ID: tenantId, AZURE_CLIENT_ID: clientId, AZURE_CLIENT_SECRET: clientSecret })) {\n  if (!v) throw new Error(`missing Azure credential: ${k}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  token = await getAzureToken(tenantId, clientId, clientSecret);\n} catch (error) {\n  if (/400/.test(String(error))) throw new Error('invalid/expired AZURE_CLIENT_SECRET or wrong client id');\n  if (/401/.test(String(error))) throw new Error('wrong AZURE_TENANT_ID');\n  throw error;\n}","preventionTips":["Set calendar reminders for service-principal secret expiry","Assert every AZURE_* secret is non-empty right after getSecret, before any network call","Verify the principal with `az login --service-principal` when in doubt"],"tags":["azure","auth","secrets","ci"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}