apache/hadoop · error · IOException
Wrong key length. Required ${bitLength}, but got ${actualBit
Error message
Wrong key length. Required ${bitLength}, but got ${actualBitLength} What it means
UserProvider.createKey enforces the same size invariant as the keystore provider: options.getBitLength() must equal 8 * material.length, so the bytes stored in the user's credential store always match the Metadata created for the key. The check runs before any credential entry is added, so a rejected call leaves no partial state.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/UserProvider.java:90
}
byte[] serialized = credentials.getSecretKey(new Text(name));
if (serialized == null) {
return null;
}
Metadata result = new Metadata(serialized);
cache.put(name, result);
return result;
}
@Override
public synchronized KeyVersion createKey(String name, byte[] material,
Options options) throws IOException {
Text nameT = new Text(name);
if (credentials.getSecretKey(nameT) != null) {
throw new IOException("Key " + name + " already exists in " + this);
}
if (options.getBitLength() != 8 * material.length) {
throw new IOException("Wrong key length. Required " +
options.getBitLength() + ", but got " + (8 * material.length));
}
Metadata meta = new Metadata(options.getCipher(), options.getBitLength(),
options.getDescription(), options.getAttributes(), new Date(), 1);
cache.put(name, meta);
String versionName = buildVersionName(name, 0);
credentials.addSecretKey(nameT, meta.serialize());
credentials.addSecretKey(new Text(versionName), material);
return new KeyVersion(name, versionName, material);
}
@Override
public synchronized void deleteKey(String name) throws IOException {
Metadata meta = getMetadata(name);
if (meta == null) {
throw new IOException("Key " + name + " does not exist in " + this);
}
for(int v=0; v < meta.getVersions(); ++v) {View on GitHub (pinned to 2add963021)
Solutions
- Allocate material as new byte[options.getBitLength() / 8] and fill with SecureRandom
- Prefer generateKey(bitLength, cipher) or the one-arg createKey(name, options) overload
- Validate material.length == options.getBitLength() / 8 before the call
Example fix
// before
Options opts = new Options(conf).setCipher("AES").setBitLength(256);
byte[] material = new byte[16];
provider.createKey(name, material, opts);
// after
Options opts = new Options(conf).setCipher("AES").setBitLength(256);
byte[] material = KeyProvider.generateKey(opts.getBitLength(), "AES");
provider.createKey(name, material, opts); Defensive patterns
Strategy: validation
Validate before calling
if (material == null || 8 * material.length != options.getBitLength()) {
throw new IllegalArgumentException("material bits=" + (material == null ? 0 : 8 * material.length) + ", required=" + options.getBitLength());
}
provider.createKey(name, material, options); Try / catch
catch (IOException e) { if (String.valueOf(e.getMessage()).startsWith("Wrong key length")) { material = KeyProvider.generateKey(options.getBitLength(), options.getCipher()); provider.createKey(name, material, options); } else { throw e; } } Prevention
- Derive material size from options.getBitLength()/8
- Use generateKey or createKey(name, options) overloads
- Never hard-code 16-byte material in shared helpers
When it happens
Trigger: Options built with setBitLength(256) while passing a 16-byte array; 32 random bytes passed with default (128-bit) Options; generation code sized independently of the options object.
Common situations: Shared example code with hard-coded 16-byte material; upgrading key size without touching generation logic; tests using arbitrary strings as material.
Related errors
- Wrong key length. Required ${options.getBitLength()}, but go
- Wrong key length. Required ${meta.getBitLength()}, but got $
- 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/b1d4641ce86c173a.
Report an issue: GitHub.