OtterMind/Chat2DB · error · BusinessException
api.privateKeyNotFound
api.privateKeyNotFound
Error message
api.privateKeyNotFound
What it means
BusinessException 'api.privateKeyNotFound' from stringToPrivateKey when the organization-token string cannot be Base64-decoded into a valid PKCS8 RSA private key. The KeyFactory/KeySpec step throws, meaning the supplied key material is malformed or not actually a private key.
Source
Thrown at chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbWorkspaceDataSourceServiceImpl.java:231
if (StringUtils.isNotBlank(dataSource.getHost())) {
dataSource.setHost(decryptToken(dataSource.getHost(), privateKey));
}
if (StringUtils.isNotBlank(dataSource.getUrl())) {
dataSource.setUrl(decryptToken(dataSource.getUrl(), privateKey));
}
if (StringUtils.isNotBlank(dataSource.getUser())) {
dataSource.setUser(decryptToken(dataSource.getUser(), privateKey));
}
}
private PrivateKey stringToPrivateKey(String privateKeyString) {
try {
byte[] keyBytes = Base64.getDecoder().decode(privateKeyString);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
throw new BusinessException("api.privateKeyNotFound");
}
}
private String decryptToken(String encryptedToken, PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedToken));
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
log.error("decrypt token error", e);
throw new BusinessException("api.decryptPasswordError");
}
}
private String decryptString(String password) {
if (password == null || password.isEmpty()) {
return password;View on GitHub (pinned to 5ee1e990e7)
Solutions
- Re-authenticate to obtain a fresh organization token matching the server's current key pair.
- Confirm the token is a PKCS8 private key (Base64 of DER, not PEM-wrapped or a public key).
- Check for whitespace/newlines accidentally included in the token value.
- Verify the server-side key provisioning generated a valid RSA private key.
Defensive patterns
Strategy: try-catch
Validate before calling
// sanity check the token shape before use
String tok = ctx.getOrganizationToken();
if (tok == null || tok.length() < 100) throw new IllegalArgumentException("organization token looks invalid");
try { Base64.getDecoder().decode(tok); } catch (IllegalArgumentException ex) { throw new IllegalArgumentException("token is not base64"); } Try / catch
try { PrivateKey k = stringToPrivateKey(token); }
catch (BusinessException e) {
// recover by forcing re-auth rather than continuing with a bad key
throw new NeedLoggedInBusinessException();
} Prevention
- Treat 'api.privateKeyNotFound' as an auth failure — re-authenticate to refresh the token.
- Do not hand-edit or truncate the organization token.
- Validate token is Base64 + reasonable length before passing to KeyFactory.
When it happens
Trigger: decryptSensitiveFields receives a non-null organizationToken that is corrupt, truncated, not PKCS8 DER, or is a public key string. Base64.getDecoder().decode or KeyFactory.generatePrivate then fails.
Common situations: Org token overwritten with a placeholder; token from a different key pair (public key only); copy/paste truncation or whitespace in the token; key regenerated server-side but client holds a stale token.
Related errors
- common.needLoggedIn
- api.decryptPasswordError
- The baseURL is not valid!
- The baseURL is not valid!
- Decryption error
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/3945f3dabc632087.
Report an issue: GitHub.