{"record":{"id":"720ff86e8fbc561e","repo":"apache/hadoop","slug":"missing-keyfile-property-s-for-authentication","errorCode":null,"errorMessage":"Missing keyfile property ('%s') for authentication type '%s'","messagePattern":"Missing keyfile property \\('(.+?)'\\) for authentication type '(.+?)'","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/HadoopCredentialsConfiguration.java","lineNumber":142,"sourceCode":"    GoogleCredentials credentials = getCredentialsInternal(config, keyPrefixes);\n    return credentials == null ? null : configureCredentials(config, keyPrefixes, credentials);\n  }\n\n  private static GoogleCredentials getCredentialsInternal(\n          Configuration config, List<String> keyPrefixes) throws IOException {\n    AuthenticationType authenticationType =\n            AUTHENTICATION_TYPE_SUFFIX.withPrefixes(keyPrefixes).get(config, config::getEnum);\n    switch (authenticationType) {\n    case APPLICATION_DEFAULT:\n      return GoogleCredentials.getApplicationDefault();\n    case COMPUTE_ENGINE:\n      return ComputeEngineCredentials.newBuilder().build();\n    case SERVICE_ACCOUNT_JSON_KEYFILE:\n      String keyFile = SERVICE_ACCOUNT_JSON_KEYFILE_SUFFIX\n              .withPrefixes(keyPrefixes).get(config, config::get);\n\n      if (Strings.isNullOrEmpty(keyFile)) {\n        throw new IllegalArgumentException(String.format(\n                \"Missing keyfile property ('%s') for authentication type '%s'\",\n                SERVICE_ACCOUNT_JSON_KEYFILE_SUFFIX.getKey(),\n                authenticationType));\n      }\n\n      try (FileInputStream fis = new FileInputStream(keyFile)) {\n        return ServiceAccountCredentials.fromStream(fis);\n      }\n    case USER_CREDENTIALS:\n      String clientId = AUTH_CLIENT_ID_SUFFIX.withPrefixes(keyPrefixes).get(config, config::get);\n      RedactedString clientSecret =\n              AUTH_CLIENT_SECRET_SUFFIX.withPrefixes(keyPrefixes).getPassword(config);\n      RedactedString refreshToken =\n              AUTH_REFRESH_TOKEN_SUFFIX.withPrefixes(keyPrefixes).getPassword(config);\n\n      return UserCredentials.newBuilder()\n              .setClientId(clientId)\n              .setClientSecret(clientSecret.getValue())","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/HadoopCredentialsConfiguration.java#L124-L160","documentation":"HadoopCredentialsConfiguration.getCredentials: when the authentication type property is SERVICE_ACCOUNT_JSON_KEYFILE, the keyfile property (key suffix .auth.service.account.json.keyfile, resolved under configured prefixes such as fs.gs and the google.cloud base prefix - e.g. fs.gs.auth.service.account.json.keyfile) must be non-empty. If it is null/empty, IllegalArgumentException names the exact missing key.","triggerScenarios":"Setting fs.gs.auth.type (or google.cloud.auth.type) to SERVICE_ACCOUNT_JSON_KEYFILE without setting fs.gs.auth.service.account.json.keyfile / google.cloud.auth.service.account.json.keyfile; setting the keyfile under the wrong prefix so resolution falls through to empty.","commonSituations":"Switching a cluster from default COMPUTE_ENGINE auth (the built-in default) to keyfile auth but only editing one property; typos in the long property name; keyfile path configured on the client but missing from NodeManager/DataNode configs; CI using stripped-down core-site.xml.","solutions":["Set fs.gs.auth.service.account.json.keyfile (and/or google.cloud.auth.service.account.json.keyfile) to the absolute path of the service-account JSON key in core-site.xml or the job Configuration.","Verify the path is readable on every node that instantiates the FileSystem, not just the client.","If no keyfile is intended, switch the auth type back (e.g. APPLICATION_DEFAULT or COMPUTE_ENGINE).","Check for typos/prefix mismatches against the exact key name printed in the exception message."],"exampleFix":"<!-- before (core-site.xml) -->\n<property><name>fs.gs.auth.type</name><value>SERVICE_ACCOUNT_JSON_KEYFILE</value></property>\n<!-- keyfile property missing -> IllegalArgumentException -->\n\n<!-- after -->\n<property><name>fs.gs.auth.type</name><value>SERVICE_ACCOUNT_JSON_KEYFILE</value></property>\n<property>\n  <name>fs.gs.auth.service.account.json.keyfile</name>\n  <value>/etc/hadoop/conf/gcs-service-account.json</value>\n</property>","handlingStrategy":"validation","validationCode":"String type = conf.get(\"fs.gs.auth.type\", \"google.cloud.auth.type\" /*fallback*/);\nif (\"SERVICE_ACCOUNT_JSON_KEYFILE\".equals(conf.get(\"fs.gs.auth.type\"))) {\n  String keyfile = conf.get(\"fs.gs.auth.service.account.json.keyfile\",\n      conf.get(\"google.cloud.auth.service.account.json.keyfile\"));\n  if (keyfile == null || keyfile.isEmpty()) {\n    throw new IllegalArgumentException(\"Set fs.gs.auth.service.account.json.keyfile\");\n  }\n}","typeGuard":null,"tryCatchPattern":"catch IllegalArgumentException with message startsWith(\"Missing keyfile property\") - the message names the exact key to set; add it to core-site.xml / job conf and re-initialize the FileSystem.","preventionTips":["Whenever switching fs.gs.auth.type to SERVICE_ACCOUNT_JSON_KEYFILE, set the keyfile property in the same change.","Distribute auth properties to every node's config, not only the client.","Use config linting or startup validation for required auth property pairs."],"tags":["authentication","gcs","hadoop","configuration","service-account"],"backgroundTag":"missing-auth-config","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}