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
- Size the material to exactly options.getBitLength() / 8 bytes (e.g. 32 bytes for 256-bit)
- Prefer KeyProvider.generateKey(bitLength, cipher) or the one-arg createKey(name, options) overload, which build correctly sized material for you
- 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
- Always derive material size from options.getBitLength()/8
- Use generateKey()/createKey(name, options) overloads instead of hand-built material
- In tests, build material via KeyProvider.generateKey so length stays consistent
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
- Wrong key length. Required ${meta.getBitLength()}, but got $
- Wrong key length. Required ${bitLength}, but got ${actualBit
- Key ${name} does not exist in ${this}
- Key ${name} not found
- attributes cannot have a NULL key
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/2f3792a91fd4e168.
Report an issue: GitHub.