{"record":{"id":"5858dd528a987d08","repo":"grpc/grpc-java","slug":"at-least-one-credential-is-required","errorCode":null,"errorMessage":"At least one credential is required","messagePattern":"At least one credential is required","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/io/grpc/ChoiceChannelCredentials.java","lineNumber":37,"sourceCode":"import static java.util.Collections.unmodifiableList;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Provides a list of {@link ChannelCredentials}, where any one may be used. The credentials are in\n * preference order.\n */\npublic final class ChoiceChannelCredentials extends ChannelCredentials {\n  /**\n   * Constructs with the provided {@code creds} as options, with preferred credentials first.\n   *\n   * @throws IllegalArgumentException if no creds are provided\n   */\n  public static ChannelCredentials create(ChannelCredentials... creds) {\n    if (creds.length == 0) {\n      throw new IllegalArgumentException(\"At least one credential is required\");\n    }\n    for (ChannelCredentials cred : creds) {\n      if (cred == null) {\n        throw new NullPointerException();\n      }\n    }\n    return new ChoiceChannelCredentials(unmodifiableList(new ArrayList<>(Arrays.asList(creds))));\n  }\n\n  private final List<ChannelCredentials> creds;\n\n  private ChoiceChannelCredentials(List<ChannelCredentials> creds) {\n    this.creds = creds;\n  }\n\n  /** Non-empty list of credentials, in preference order. */\n  public List<ChannelCredentials> getCredentialsList() {\n    return creds;","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/api/src/main/java/io/grpc/ChoiceChannelCredentials.java#L19-L55","documentation":"ChoiceChannelCredentials.create() builds a credentials object that tries its options in preference order. It requires at least one credential; calling create() with an empty varargs array throws IllegalArgumentException before any null check.","triggerScenarios":"Calling ChannelCredentials.create() / ChoiceChannelCredentials.create() with zero arguments, e.g. from a spread of an empty collection like creds.toArray(new ChannelCredentials[0]) where the list is empty, or omitting arguments entirely.","commonSituations":"Dynamically building a credential list from configuration (TLS disabled or keys absent) and passing the (possibly empty) result; a config file whose credential section was dropped; refactoring that removed the default fallback credential.","solutions":["Ensure at least one ChannelCredentials is always provided, e.g. prepend a fallback like TlsChannelCredentials.create() or InsecureChannelCredentials.create()","Validate the credential list is non-empty before calling create() and surface a clear configuration error","Fix the configuration source so the credentials section is populated (cert/key files present)"],"exampleFix":"// before\nChannelCredentials creds = ChoiceChannelCredentials.create(configuredCreds.toArray(new ChannelCredentials[0]));\n// after\nif (configuredCreds.isEmpty()) {\n  configuredCreds.add(InsecureChannelCredentials.create()); // or fail fast with a config error\n}\nChannelCredentials creds = ChoiceChannelCredentials.create(configuredCreds.toArray(new ChannelCredentials[0]));","handlingStrategy":"validation","validationCode":"if (credList == null || credList.isEmpty()) {\n  throw new IllegalArgumentException(\"At least one ChannelCredentials must be configured\");\n}\nChannelCredentials creds = ChoiceChannelCredentials.create(credList.toArray(new ChannelCredentials[0]));","typeGuard":null,"tryCatchPattern":"try {\n  ChannelCredentials creds = ChoiceChannelCredentials.create(credArray);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"At least one credential is required\")) {\n    creds = InsecureChannelCredentials.create(); // or surface a config error\n  } else throw e;\n}","preventionTips":["Always include a fallback credential (TLS or insecure) when building the list dynamically","Validate non-empty credential configuration at application startup, not at channel creation","Fail fast with a descriptive message when the credentials config section is missing"],"tags":["illegal-argument","credentials","validation","channel"],"backgroundTag":"missing-required-argument","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"}