{"record":{"id":"291bf7b17f00c4b7","repo":"grpc/grpc-java","slug":"key-s-missing-in-s","errorCode":null,"errorMessage":"key '%s' missing in '%s'","messagePattern":"key '(.+?)' missing in '(.+?)'","errorType":"validation","errorClass":"VerifyException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/DnsNameResolver.java","lineNumber":512,"sourceCode":"      }\n    }\n    List<String> clientHostnames = getHostnamesFromChoice(choice);\n    if (clientHostnames != null && !clientHostnames.isEmpty()) {\n      boolean hostnamePresent = false;\n      for (String clientHostname : clientHostnames) {\n        if (clientHostname.equals(hostname)) {\n          hostnamePresent = true;\n          break;\n        }\n      }\n      if (!hostnamePresent) {\n        return null;\n      }\n    }\n    Map<String, ?> sc =\n        JsonUtil.getObject(choice, SERVICE_CONFIG_CHOICE_SERVICE_CONFIG_KEY);\n    if (sc == null) {\n      throw new VerifyException(String.format(\n          \"key '%s' missing in '%s'\", choice, SERVICE_CONFIG_CHOICE_SERVICE_CONFIG_KEY));\n    }\n    return sc;\n  }\n\n  /**\n   * Describes a parsed SRV record.\n   */\n  @VisibleForTesting\n  public static final class SrvRecord {\n    public final String host;\n    public final int port;\n\n    public SrvRecord(String host, int port) {\n      this.host = host;\n      this.port = port;\n    }\n","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/DnsNameResolver.java#L494-L530","documentation":"Each service-config choice from DNS must contain the `serviceConfig` key. In maybeChooseServiceConfig, after selecting a choice map, if the `serviceConfig` key is absent, the resolver throws a VerifyException describing which choice failed - the selection cannot produce a usable service config.","triggerScenarios":"A DNS TXT `grpc_config` choice object that lacks the `serviceConfig` key (or has it misspelled / null), so JsonUtil.getObject returns null during service-config selection.","commonSituations":"Wrong service-config schema published in DNS (older or hand-written choices); fields renamed after a spec change; partial records produced by automation that failed mid-write.","solutions":["Publish the choice as an object containing a non-null `serviceConfig` key, e.g. {\"clientLanguage\":..., \"serviceConfig\":{...}}.","Validate DNS TXT service-config choices against the gRPC service-config-choice schema before publishing.","Remove malformed choices so the resolver can pick a valid one."],"exampleFix":"// before (TXT record)\ngrpc_config=[{\"clientLanguage\":\"java\"}]\n// after (TXT record)\ngrpc_config=[{\"clientLanguage\":\"java\",\"serviceConfig\":{...}}]","handlingStrategy":"validation","validationCode":"Map<String, ?> choice = JsonUtil.getObject(raw, ...);\nif (choice == null || !choice.containsKey(\"serviceConfig\")) {\n  throw new IllegalArgumentException(\"service config choice lacks 'serviceConfig' key\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  sc = maybeChooseServiceConfig(choice);\n} catch (VerifyException e) {\n  // skip malformed choice, use default service config\n}","preventionTips":["Validate published service-config choices against the gRPC schema.","Include a non-null serviceConfig key in every choice object.","Test DNS resolution against the published records in CI."],"tags":["grpc","dns","service-config","missing-key"],"backgroundTag":"missing-required-config-field","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}