{"id":"4e1c01c0aedf063b","repo":"mongodb/node-mongodb-native","slug":"malformed-json-body-in-get-request","errorCode":null,"errorMessage":"Malformed JSON body in GET request.","messagePattern":"Malformed JSON body in GET request\\.","errorType":"exception","errorClass":"MongoCryptAzureKMSRequestError","httpStatus":null,"severity":"error","filePath":"src/client-side-encryption/providers/azure.ts","lineNumber":75,"sourceCode":"    return fetchAzureKMSToken();\n  }\n}\n\n/** @internal */\nexport const tokenCache = new AzureCredentialCache();\n\n/** @internal */\nasync function parseResponse(response: {\n  body: string;\n  status?: number;\n}): Promise<AzureTokenCacheEntry> {\n  const { status, body: rawBody } = response;\n\n  const body: { expires_in?: number; access_token?: string } = (() => {\n    try {\n      return JSON.parse(rawBody);\n    } catch {\n      throw new MongoCryptAzureKMSRequestError('Malformed JSON body in GET request.');\n    }\n  })();\n\n  if (status !== 200) {\n    throw new MongoCryptAzureKMSRequestError('Unable to complete request.', body);\n  }\n\n  if (!body.access_token) {\n    throw new MongoCryptAzureKMSRequestError(\n      'Malformed response body - missing field `access_token`.'\n    );\n  }\n\n  if (!body.expires_in) {\n    throw new MongoCryptAzureKMSRequestError(\n      'Malformed response body - missing field `expires_in`.'\n    );\n  }","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/client-side-encryption/providers/azure.ts#L57-L93","documentation":"Thrown by the CSFLE Azure KMS credential provider when the HTTP response body from the Azure Instance Metadata Service (IMDS) endpoint (169.254.169.254) cannot be parsed as JSON. The driver calls this endpoint to fetch an access token for Azure Key Vault when automatic KMS credentials are used. A non-JSON body indicates the endpoint returned HTML (e.g. a proxy error page), an empty body, or otherwise corrupt content.","triggerScenarios":"Triggered inside parseResponse() when JSON.parse(rawBody) throws, which is called from fetchAzureKMSToken() during CSFLE/AutoEncryption startup or token refresh when no explicit azure KMS provider credentials were supplied.","commonSituations":"Running CSFLE on a machine that is NOT an Azure VM (so 169.254.169.254 returns nothing or a captive-portal HTML page); corporate HTTP proxy intercepting the link-local address and returning HTML; network policy blocking the IMDS endpoint and returning an error page; attempting local development of CSFLE without providing explicit azure credentials.","solutions":["If not running on an Azure VM, supply explicit Azure KMS credentials in the KMS providers map instead of relying on IMDS auto-detection.","Verify the host can reach 169.254.169.254: curl -H 'Metadata: true' 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net'","Disable or bypass any HTTP proxy for the link-local IP 169.254.169.254.","Check that a system-assigned or user-assigned managed identity is enabled on the Azure VM."],"exampleFix":"// before\nconst client = new MongoClient(uri, {\n  autoEncryption: { keyVaultNamespace: 'encryption.__dataKeys', kmsProviders: {} }\n});\n\n// after (explicit credentials when not on Azure VM)\nconst kmsProviders = { azure: { tenantId, clientId, clientSecret } };\nconst client = new MongoClient(uri, {\n  autoEncryption: { keyVaultNamespace: 'encryption.__dataKeys', kmsProviders }\n});","handlingStrategy":"try-catch","validationCode":"// Before constructing the AutoEncryption client, decide whether IMDS is reachable.\nasync function canReachAzureIMDS(): Promise<boolean> {\n  try {\n    const controller = new AbortController();\n    const t = setTimeout(() => controller.abort(), 2000);\n    const res = await fetch(\n      'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net',\n      { headers: { Metadata: 'true' }, signal: controller.signal }\n    );\n    clearTimeout(t);\n    if (!res.ok) return false;\n    await res.json(); // throws if not JSON\n    return true;\n  } catch {\n    return false;\n  }\n}\nconst kmsProviders = (await canReachAzureIMDS()) ? {} : { azure: { tenantId, clientId, clientSecret } };","typeGuard":"import { MongoCryptAzureKMSRequestError } from 'mongodb';\nfunction isAzureKMSError(e: unknown): e is MongoCryptAzureKMSRequestError {\n  return e instanceof MongoCryptAzureKMSRequestError;\n}","tryCatchPattern":"try {\n  const client = new MongoClient(uri, { autoEncryption: { kmsProviders, keyVaultNamespace } });\n  await client.connect();\n} catch (err) {\n  if (err instanceof MongoCryptAzureKMSRequestError && /Malformed JSON/.test(err.message)) {\n    // IMDS not reachable; supply explicit azure credentials and retry.\n  }\n  throw err;\n}","preventionTips":["In local/dev environments, always supply explicit azure KMS credentials rather than relying on IMDS.","Block-test the IMDS endpoint during deployment smoke checks.","Document the link-local IP allow-list requirement for any network namespace."],"tags":["csfle","azure-kms","network","queryable-encryption"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}