{"record":{"id":"314cbb2b95af4c0a","repo":"grpc/grpc-java","slug":"spiffe-trust-bundle-should-be-a-json-object-found","errorCode":null,"errorMessage":"SPIFFE Trust Bundle should be a JSON object. Found: ${type}","messagePattern":"SPIFFE Trust Bundle should be a JSON object\\. Found: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/SpiffeUtil.java","lineNumber":195,"sourceCode":"      }\n      Long sequenceNumber = JsonUtil.getNumberAsLong(domainNode, \"spiffe_sequence\");\n      sequenceNumbers.put(trustDomainName, sequenceNumber == null ? -1L : sequenceNumber);\n      List<Map<String, ?>> keysNode = JsonUtil.getListOfObjects(domainNode, \"keys\");\n      if (keysNode == null || keysNode.size() == 0) {\n        trustBundleMap.put(trustDomainName, Collections.emptyList());\n        continue;\n      }\n      trustBundleMap.put(trustDomainName, extractCert(keysNode, trustDomainName));\n    }\n    return new SpiffeBundle(sequenceNumbers, trustBundleMap);\n  }\n\n  private static Map<String, ?> readTrustDomainsFromFile(String filePath) throws IOException {\n    File file = new File(checkNotNull(filePath, \"trustBundleFile\"));\n    String json = new String(Files.toByteArray(file), StandardCharsets.UTF_8);\n    Object jsonObject = JsonParser.parse(json);\n    if (!(jsonObject instanceof Map)) {\n      throw new IllegalArgumentException(\n          \"SPIFFE Trust Bundle should be a JSON object. Found: \"\n              + (jsonObject == null ? null : jsonObject.getClass()));\n    }\n    @SuppressWarnings(\"unchecked\")\n    Map<String, ?> root = (Map<String, ?>)jsonObject;\n    Map<String, ?> trustDomainsNode = JsonUtil.getObject(root, \"trust_domains\");\n    checkNotNull(trustDomainsNode, \"Mandatory trust_domains element is missing\");\n    checkArgument(trustDomainsNode.size() > 0, \"Mandatory trust_domains element is missing\");\n    return trustDomainsNode;\n  }\n\n  private static void checkJwkEntry(Map<String, ?> jwkNode, String trustDomainName) {\n    String kty = JsonUtil.getString(jwkNode, \"kty\");\n    if (kty == null || !KTY_PARAMETER_VALUES.contains(kty)) {\n      throw new IllegalArgumentException(\n          String.format(\n              \"'kty' parameter must be one of %s but '%s' \"\n                  + \"found. Certificate loading for trust domain '%s' failed.\",","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/SpiffeUtil.java#L177-L213","documentation":"SpiffeUtil.readTrustDomainsFromFile loads a SPIFFE trust bundle file and parses it as JSON. The top-level document must be a JSON object (map) containing trust_domains; if the parsed JSON is an array, string, number, or null, this IllegalArgumentException reports the actual Java type found.","triggerScenarios":"Pointing the SPIFFE trust bundle file path at a file whose top-level JSON is not an object — e.g. a JSON array of keys, a bare PEM blob in a .json file, or an empty/garbled file — during trust bundle loading.","commonSituations":"Downloading the wrong endpoint payload (array of JWKs instead of the bundle object); a fetch job writing raw certificate text into the bundle path; truncated or corrupted bundle file.","solutions":["Ensure the file's top level is a JSON object like {\"trust_domains\": {\"domain\": {\"keys\": [...]}}}, keyed under trust_domains","Verify the file with: python3 -c 'import json;d=json.load(open(\"bundle.json\"));print(type(d))' — must be dict","Re-fetch the bundle from your SPIFFE workload API (SPIRE agent api/1/spiffe/bundle) in its native object form"],"exampleFix":"// before (bundle.json)\n[{\"kty\":\"RSA\",\"n\":\"...\"}]\n// after\n{\"trust_domains\": {\"example.org\": {\"keys\": [{\"kty\":\"RSA\",\"n\":\"...\"}]}}}","handlingStrategy":"validation","validationCode":"// Check bundle file top-level shape before loading\nString json = new String(java.nio.file.Files.readAllBytes(path), StandardCharsets.UTF_8);\nObject parsed = org.codehaus.jettison.json or your JsonParser.parse(json);\nif (!(parsed instanceof Map)) {\n  throw new IllegalStateException(\"Trust bundle must be a JSON object, got: \"\n      + (parsed == null ? \"null\" : parsed.getClass()));\n}\nif (!((Map<?, ?>) parsed).containsKey(\"trust_domains\")) {\n  throw new IllegalStateException(\"Trust bundle missing 'trust_domains'\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  Map<String, ?> domains = trustDomainsNode(bundlePath);\n} catch (IllegalArgumentException e) {\n  log.error(\"SPIFFE trust bundle is not a JSON object: \" + e.getMessage());\n  throw new TrustBundleLoadException(e);\n}","preventionTips":["Fetch bundles from the SPIRE agent bundle endpoint in native object form","Never paste raw PEM into the .json bundle file","Atomically re-fetch and JSON-validate the bundle before swapping it in"],"tags":["grpc","spiffe","trust-bundle","json","file"],"backgroundTag":"config-type-mismatch","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}