apache/hadoop · error · UnsupportedOperationException

SASToken received is empty or null

Error message

SASToken received is empty or null

What it means

The configured SASTokenProvider returned null or an empty string for the requested path/operation. With authType validated for SAS (e.g. SAS auth selected in fs.azure.account.auth.type), a usable token is mandatory, so the client throws UnsupportedOperationException (which the enclosing catch then wraps into SASTokenProviderException).

Source

Thrown at hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java:1166

   * @param queryBuilder to which SAS token is appended.
   * @param cachedSasToken - previously acquired SAS token to be reused.
   * @return sasToken - returned for optional re-use.
   * @throws SASTokenProviderException if SAS token cannot be acquired.
   */
  protected String appendSASTokenToQuery(String path,
                                         String operation,
                                         AbfsUriQueryBuilder queryBuilder,
                                         String cachedSasToken)
      throws SASTokenProviderException {
    String sasToken = null;
    if (getAbfsConfiguration().validateForSASType(this.authType)) {
      try {
        LOG.trace("Fetch SAS token for {} on {}", operation, path);
        if (cachedSasToken == null) {
          sasToken = sasTokenProvider.getSASToken(this.accountName,
              this.filesystem, path, operation);
          if ((sasToken == null) || sasToken.isEmpty()) {
            throw new UnsupportedOperationException("SASToken received is empty or null");
          }
        } else {
          sasToken = cachedSasToken;
          LOG.trace("Using cached SAS token.");
        }

        // if SAS Token contains a prefix of ?, it should be removed
        if (sasToken.charAt(0) == '?') {
          sasToken = sasToken.substring(1);
        }

        queryBuilder.setSASToken(sasToken);
        LOG.trace("SAS token fetch complete for {} on {}", operation, path);
      } catch (Exception ex) {
        throw new SASTokenProviderException(String.format(
            "Failed to acquire a SAS token for %s on %s due to %s", operation, path,
            ex.toString()), ex);
      }

View on GitHub (pinned to 2add963021)

Solutions

  1. Fix the SASTokenProvider implementation to always return a non-empty, valid SAS token for every operation it is asked for, throwing explicitly when it genuinely cannot.
  2. Unit-test the provider directly for all operation types (read, write, delete containers) used by the workload.
  3. Verify the backing secret store entry exists, is enabled, and is readable by the provider's credentials.

Example fix

// before (custom provider)
public String getSASToken(String account, String fs, String path, String op) {
  return cache.get(op); // null on miss
}
// after
public String getSASToken(String account, String fs, String path, String op) {
  String t = cache.computeIfAbsent(op, o -> keyVault.fetch(account, fs, o));
  if (t == null || t.isEmpty()) {
    throw new SASTokenProviderException("No SAS token available for " + o);
  }
  return t;
}
Defensive patterns

Strategy: validation

Validate before calling

String t = provider.getSASToken(account, filesystem, path, op);
if (t == null || t.isEmpty()) {
  throw new IllegalStateException("SAS provider returned no token for " + op);
}

Try / catch

catch (SASTokenProviderException ex) {
  if (ex.getCause() instanceof UnsupportedOperationException
      && ex.getCause().getMessage().contains("empty or null")) {
    // provider returned no token: fix the provider implementation
  } else throw ex;
}

Prevention

When it happens

Trigger: A custom SASTokenProvider implementation whose getSASToken() returns null/empty for some operation type or path — commonly an unimplemented operation branch, an expired/missing secret read that returns null instead of throwing, or scope filters that skip the requested container.

Common situations: Custom KeyVault-backed providers returning null when a secret is disabled; providers written for read operations only, returning null for writes (like the delete-container operation); test providers stubbed with null.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/1db00013f155d1ba. Report an issue: GitHub.