oven-sh/bun · error
Azure auth failed: ${response.status}
Error message
Azure auth failed: ${response.status} What it means
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).
Source
Thrown at scripts/machine.mjs:1140
* @property {number} [memoryGb]
* @property {number} [diskSizeGb]
* @property {boolean} [preemptible]
* @property {boolean} [detached]
* @property {Record<string, unknown>} [tags]
* @property {boolean} [bootstrap]
* @property {boolean} [ci]
* @property {boolean} [rdp]
* @property {string} [userData]
* @property {SshKey[]} sshKeys
*/
async function getAzureToken(tenantId, clientId, clientSecret) {
const response = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `grant_type=client_credentials&client_id=${clientId}&client_secret=${encodeURIComponent(clientSecret)}&scope=https://management.azure.com/.default`,
});
if (!response.ok) throw new Error(`Azure auth failed: ${response.status}`);
const data = await response.json();
return data.access_token;
}
/**
* Build a Windows image using Packer (Azure only).
* Packer handles VM creation, bootstrap, sysprep, and gallery capture via WinRM.
* This eliminates all the Azure Run Command issues (output truncation, x64 emulation,
* PATH not refreshing, stderr false positives, quote escaping).
*/
async function buildWindowsImageWithPacker({ os, arch, release, command, ci, agentPath, bootstrapPath }) {
const { getSecret } = await import("./utils.mjs");
// Determine Packer template
const templateName = arch === "aarch64" ? "windows-arm64" : "windows-x64";
const templateDir = resolve(import.meta.dirname, "packer");
const templateFile = join(templateDir, `${templateName}.pkr.hcl`);
View on GitHub (pinned to 8c5296ac45)
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
Example fix
// before
const token = await getAzureToken(tenantId, clientId, clientSecret);
// after
for (const [k, v] of Object.entries({ tenantId, clientId, clientSecret })) {
if (!v) throw new Error(`missing Azure credential: ${k}`);
}
const token = await getAzureToken(tenantId, clientId, clientSecret); Defensive patterns
Strategy: validation
Validate before calling
for (const [k, v] of Object.entries({ AZURE_TENANT_ID: tenantId, AZURE_CLIENT_ID: clientId, AZURE_CLIENT_SECRET: clientSecret })) {
if (!v) throw new Error(`missing Azure credential: ${k}`);
} Try / catch
try {
token = await getAzureToken(tenantId, clientId, clientSecret);
} catch (error) {
if (/400/.test(String(error))) throw new Error('invalid/expired AZURE_CLIENT_SECRET or wrong client id');
if (/401/.test(String(error))) throw new Error('wrong AZURE_TENANT_ID');
throw error;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Service principal secret past its expiry in CI; getSecret() returning empty because the Buildkite secret wasn't created; tenant GUID copy-paste error.
Related errors
- Azure secret not found: ${name}
- Buildkite token not found: set BUILDKITE_AGENT_TOKEN or gran
- [azure] Auth failed: ${response.status} ${await response.tex
- [azure] Unsupported OS: ${os}
- [azure] Failed to get public IP for ${vmName}
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/8a4dfb55aa9ca617.
Report an issue: GitHub.