{"record":{"id":"efd9e547d1f5dc36","repo":"apache/beam","slug":"could-not-access-keytab-file-make-sure-that-the-sasl-jaas","errorCode":null,"errorMessage":"Could not access keytab file. Make sure that the sasl.jaas.config config property is set correctly.","messagePattern":"Could not access keytab file\\. Make sure that the sasl\\.jaas\\.config config property is set correctly\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/kafka-factories/src/main/java/org/apache/beam/sdk/extensions/kafka/factories/KerberosConsumerFactoryFn.java","lineNumber":80,"sourceCode":"    // property will have had it's value replaced with a local directory.\n    // We don't need to worry about the external bucket prefix in this case.\n    try {\n      String jaasConfig = (String) config.get(JAAS_CONFIG_PROPERTY);\n      String localKeytabPath = \"\";\n      if (jaasConfig != null && !jaasConfig.isEmpty()) {\n        localKeytabPath =\n            jaasConfig.substring(\n                jaasConfig.indexOf(\"keyTab=\\\"\") + 8, jaasConfig.lastIndexOf(\"\\\" principal\"));\n      }\n\n      // Set the permissions on the file to be as strict as possible for security reasons. The\n      // keytab contains sensitive information and should be as locked down as possible.\n      Path path = Paths.get(localKeytabPath);\n      Set<PosixFilePermission> perms = new HashSet<>();\n      perms.add(PosixFilePermission.OWNER_READ);\n      Files.setPosixFilePermissions(path, perms);\n    } catch (IOException e) {\n      throw new RuntimeException(\n          \"Could not access keytab file. Make sure that the sasl.jaas.config config property \"\n              + \"is set correctly.\",\n          e);\n    }\n    return new KafkaConsumer<>(config);\n  }\n\n  @Override\n  protected void downloadAndProcessExtraFiles() throws IOException {\n    synchronized (lock) {\n      // we only want a new krb5 file if there is not already one present.\n      if (localKrb5ConfPath.isEmpty()) {\n        if (this.krb5ConfigPath != null && !this.krb5ConfigPath.isEmpty()) {\n          String localPath =\n              super.getBaseDirectory() + \"/\" + LOCAL_FACTORY_TYPE + \"/\" + \"krb5.conf\";\n          localKrb5ConfPath = downloadExternalFile(this.krb5ConfigPath, localPath);\n\n          System.setProperty(\"java.security.krb5.conf\", localKrb5ConfPath);","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/kafka-factories/src/main/java/org/apache/beam/sdk/extensions/kafka/factories/KerberosConsumerFactoryFn.java#L62-L98","documentation":"After downloading the keytab to a local path, KerberosConsumerFactoryFn tightens its POSIX permissions to owner-read-only. If Files.setPosixFilePermissions throws IOException (file missing or filesystem without POSIX support), it rethrows a RuntimeException telling the user to check sasl.jaas.config. The message points at the config because the local keytab path derives from it.","triggerScenarios":"The keytab referenced in sasl.jaas.config was not written to localKeytabPath (secret processing failed or path mismatch), or the worker filesystem (e.g. some Windows/network mounts) doesn't support POSIX permissions.","commonSituations":"Missing or empty sasl.jaas.config key; secret download silently skipped; container using a volume that doesn't support POSIX perms; typo'd keytab path template.","solutions":["Verify sasl.jaas.config correctly references the keytab secret so the file is downloaded to localKeytabPath before this code runs","Check the chained IOException cause — FileNotFoundException means the keytab never landed at localKeytabPath","Ensure the worker staging directory is on a POSIX-supporting filesystem","Log/inspect localKeytabPath and confirm the file exists before constructing the consumer"],"exampleFix":"// before\nprops.put(\"sasl.jaas.config\", \"com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab=\\\"MISSING\\\" ...\");\n// after\nprops.put(\"sasl.jaas.config\", \"com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab=\\\"/tmp/keytab-<factory>/krb5.keytab\\\" ...\"); // path produced by secret processing","handlingStrategy":"try-catch","validationCode":"java\nif (!config.containsKey(\"sasl.jaas.config\") || config.get(\"sasl.jaas.config\").isEmpty()) {\n  throw new IllegalArgumentException(\"sasl.jaas.config must be set with a valid keyTab path\");\n}","typeGuard":null,"tryCatchPattern":"java\ntry {\n  KafkaConsumer<String,String> c = factoryFn.createObject(config);\n} catch (RuntimeException ex) {\n  if (ex.getMessage().startsWith(\"Could not access keytab file\")) {\n    log.severe(\"Keytab inaccessible at local path: \" + ex.getCause());\n  }\n}","preventionTips":["Verify the keytab secret downloads successfully before permissions are set","Use POSIX-capable volumes in worker images","Log the resolved localKeytabPath and assert file existence","Keep sasl.jaas.config keyTab path in sync with the factory's local path convention"],"tags":["java","kafka","kerberos","file-io"],"backgroundTag":"file-not-found","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}