{"record":{"id":"60ea01bc8852346b","repo":"apache/hadoop","slug":"token-mismatch-expected-token-for-service-of-ty","errorCode":null,"errorMessage":"Token mismatch: expected token for {service} of type {kind} but got a token of type {tokenKind}","messagePattern":"Token mismatch: expected token for (.+?) of type (.+?) but got a token of type (.+?)","errorType":"exception","errorClass":"DelegationTokenIOException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/auth/delegation/S3ADelegationTokens.java","lineNumber":638,"sourceCode":"  public static Token<AbstractS3ATokenIdentifier> lookupToken(\n      final Credentials credentials,\n      final Text service,\n      final Text kind)\n      throws DelegationTokenIOException {\n\n    LOG.debug(\"Looking for token for service {} in credentials\", service);\n    Token<?> token = credentials.getToken(service);\n    if (token != null) {\n      Text tokenKind = token.getKind();\n      LOG.debug(\"Found token of kind {}\", tokenKind);\n      if (kind.equals(tokenKind)) {\n        // the Oauth implementation catches and logs here; this one\n        // throws the failure up.\n        return (Token<AbstractS3ATokenIdentifier>) token;\n      } else {\n\n        // there's a token for this URI, but its not the right DT kind\n        throw new DelegationTokenIOException(\n            DelegationTokenIOException.TOKEN_MISMATCH + \": expected token\"\n            + \" for \" + service\n            + \" of type \" + kind\n            + \" but got a token of type \" + tokenKind);\n      }\n    }\n    // A token for the service was not found\n    LOG.debug(\"No token for {} found\", service);\n    return null;\n  }\n\n  /**\n   * Look up any token from the service; cast it to one of ours.\n   * @param credentials credentials\n   * @param service service to look up\n   * @return any token found or null if none was\n   * @throws ClassCastException if the token is of a wrong type.\n   */","sourceCodeStart":620,"sourceCodeEnd":656,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/auth/delegation/S3ADelegationTokens.java#L620-L656","documentation":"When selecting a delegation token from the user's credentials, S3ADelegationTokens looks up the token for the s3a service and requires its Text kind to equal the kind of the configured binding. If a token exists for that URI but with a different kind (issued by a different S3A delegation mechanism), it throws DelegationTokenIOException with the TOKEN_MISMATCH prefix instead of silently using the wrong token.","triggerScenarios":"selectToken(service, kind) finds a token whose getKind() differs from the binding's kind. E.g. credentials hold a token with kind of one binding while fs.s3a.delegation.token.binding selects another binding for the same s3a://bucket URI.","commonSituations":"Changing fs.s3a.delegation.token.binding (e.g. from SessionTokenBinding to S3ATokenBinding or vice versa) while old tokens remain in the credentials; a workflow where one component issues tokens under a different binding than the engine consuming them.","solutions":["Remove or cancel the mismatched token for that s3a URI, then rebind or re-fetch under the current binding","Keep the binding configuration identical across token issuer and all consumers","Give each job its own Credentials object instead of sharing UGI credentials across jobs with different bindings"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"Text service = new Text(fs.getCanonicalUri());\nToken<?> existing = ugi.getCredentials().getToken(service);\nif (existing != null && !expectedKind.equals(existing.getKind())) {\n  ugi.getCredentials().removeToken(service);\n  LOG.warn(\"Removed mismatched token kind {} for {}\", existing.getKind(), service);\n}","typeGuard":"static boolean tokenHasKind(Token<?> t, Text expectedKind) {\n  return t != null && expectedKind.equals(t.getKind());\n}","tryCatchPattern":"try {\n  tokens.bindToAnyDelegationToken();\n} catch (DelegationTokenIOException e) {\n  if (e.getMessage().startsWith(DelegationTokenIOException.TOKEN_MISMATCH)) {\n    credentials.removeToken(service); // token from another binding: purge, then rebind\n    tokens.bindToAnyDelegationToken();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Check token kinds before injecting credentials into jobs","Keep binding config consistent end-to-end","Never mix tokens from different bindings in one Credentials object"],"tags":["aws","s3a","delegation-token","token-binding","authentication"],"backgroundTag":"delegation-token-type-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}