apache/hadoop · error · IOException

Wrong key length. Required ${options.getBitLength()}, but go

Error message

Wrong key length. Required ${options.getBitLength()}, but got ${8 * material.length}

What it means

Thrown by JavaKeyStoreProvider.createKey(String, byte[], Options) when the supplied key material does not match the requested key size: the provider enforces options.getBitLength() == 8 * material.length so the bytes stored in the JCEKS keystore always agree with the Metadata recorded for the key. The check runs before the cache or keystore is touched, so a rejected create leaves no partial state.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/JavaKeyStoreProvider.java:451

  @Override
  public KeyVersion createKey(String name, byte[] material,
                               Options options) throws IOException {
    Preconditions.checkArgument(name.equals(StringUtils.toLowerCase(name)),
        "Uppercase key names are unsupported: %s", name);
    writeLock.lock();
    try {
      try {
        if (keyStore.containsAlias(name) || cache.containsKey(name)) {
          throw new IOException("Key " + name + " already exists in " + this);
        }
      } catch (KeyStoreException e) {
        throw new IOException("Problem looking up key " + name + " in " + this,
            e);
      }
      Metadata meta = new Metadata(options.getCipher(), options.getBitLength(),
          options.getDescription(), options.getAttributes(), new Date(), 1);
      if (options.getBitLength() != 8 * material.length) {
        throw new IOException("Wrong key length. Required " +
            options.getBitLength() + ", but got " + (8 * material.length));
      }
      cache.put(name, meta);
      String versionName = buildVersionName(name, 0);
      return innerSetKeyVersion(name, versionName, material, meta.getCipher());
    } finally {
      writeLock.unlock();
    }
  }

  @Override
  public void deleteKey(String name) throws IOException {
    writeLock.lock();
    try {
      Metadata meta = getMetadata(name);
      if (meta == null) {
        throw new IOException("Key " + name + " does not exist in " + this);
      }

View on GitHub (pinned to 2add963021)

Solutions

  1. Size the material to exactly options.getBitLength() / 8 bytes (e.g. 32 bytes for 256-bit)
  2. Prefer KeyProvider.generateKey(bitLength, cipher) or the one-arg createKey(name, options) overload, which build correctly sized material for you
  3. Add a caller-side assertion material.length == options.getBitLength() / 8 before calling so you fail with your own message

Example fix

// before
Options opts = new Options(conf).setCipher("AES").setBitLength(256);
byte[] material = new byte[16]; // 128 bits, mismatch
provider.createKey("dek", material, opts);

// after
Options opts = new Options(conf).setCipher("AES").setBitLength(256);
byte[] material = new byte[opts.getBitLength() / Byte.SIZE];
new SecureRandom().nextBytes(material);
provider.createKey("dek", material, opts);
Defensive patterns

Strategy: validation

Validate before calling

if (material == null || 8 * material.length != options.getBitLength()) {
  throw new IllegalArgumentException("material is "
      + (material == null ? 0 : 8 * material.length)
      + " bits, options require " + options.getBitLength());
}
provider.createKey(name, material, options);

Try / catch

catch (IOException e) { if (e.getMessage() != null && e.getMessage().startsWith("Wrong key length")) { // regenerate material at options.getBitLength()/8 and retry once } else { throw e; } }

Prevention

When it happens

Trigger: Calling createKey with Options built with setBitLength(256) but passing a 16-byte (128-bit) array; passing 32 random bytes while Options still carries the default bit length; hand-rolled SecureRandom fills sized independently of the options; reusing material generated for a different key size.

Common situations: Copy-pasted sample code that allocates 16 bytes but sets 256 bits; migrating from 128-bit to 256-bit AES without updating the generation code; unit tests using fixed strings like '0123456789abcdef0' of arbitrary length as material.

Related errors


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