apache/cassandra · error · ConfigurationException
Bad value for system property -D%s.Please use a value betwee
Error message
Bad value for system property -D%s.Please use a value between 4 and 30 inclusively
What it means
PasswordSaltSupplier reads the system property cassandra.auth_bcrypt_gensalt_log2_rounds to control bcrypt cost. getGensaltLogRounds() validates the value and throws ConfigurationException if it falls outside the supported 4-30 range, preventing startup with a cryptographically invalid or impractical cost factor.
Source
Thrown at src/java/org/apache/cassandra/auth/PasswordSaltSupplier.java:41
import com.google.common.annotations.VisibleForTesting;
import org.mindrot.jbcrypt.BCrypt;
import org.apache.cassandra.exceptions.ConfigurationException;
import static org.apache.cassandra.config.CassandraRelevantProperties.AUTH_BCRYPT_GENSALT_LOG2_ROUNDS;
public class PasswordSaltSupplier
{
// 2 ** GENSALT_LOG2_ROUNDS rounds of hashing will be performed.
private static final int GENSALT_LOG2_ROUNDS = getGensaltLogRounds();
@VisibleForTesting
static int getGensaltLogRounds()
{
int rounds = AUTH_BCRYPT_GENSALT_LOG2_ROUNDS.getInt();
if (rounds < 4 || rounds > 30)
throw new ConfigurationException(String.format("Bad value for system property -D%s." +
"Please use a value between 4 and 30 inclusively",
AUTH_BCRYPT_GENSALT_LOG2_ROUNDS.getKey()));
return rounds;
}
private static Supplier<String> DEFAULT_SALT_SUPPLIER = () -> BCrypt.gensalt(GENSALT_LOG2_ROUNDS);
private static Supplier<String> saltSupplier = DEFAULT_SALT_SUPPLIER;
public static void unsafeSet(Supplier<String> newSaltSupplier)
{
assert newSaltSupplier != null;
saltSupplier = newSaltSupplier;
}
public static void unsafeReset()
{
saltSupplier = DEFAULT_SALT_SUPPLIER;
}
public static String get()View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Set the property to an integer between 4 and 30 inclusive (10-12 is typical)
- Remove the -D flag entirely to use the default bcrypt cost
- Fix the value in the startup script/systemd unit/cassandra-env.sh where it is defined
Example fix
// before JVM_OPTS="$JVM_OPTS -Dcassandra.auth_bcrypt_gensalt_log2_rounds=50" // after JVM_OPTS="$JVM_OPTS -Dcassandra.auth_bcrypt_gensalt_log2_rounds=12"
Defensive patterns
Strategy: validation
Validate before calling
int v = Integer.parseInt(System.getProperty("cassandra.auth_bcrypt_gensalt_log2_rounds", "10")); if (v < 4 || v > 30) fail("bcrypt rounds must be 4-30"); Type guard
boolean isValidGensaltRounds(String v) { try { int n = Integer.parseInt(v); return n >= 4 && n <= 30; } catch (NumberFormatException e) { return false; } } Try / catch
try { startWith(opts); } catch (ConfigurationException e) { if (e.getMessage().contains("4 and 30")) fallbackToDefaultRounds(); } Prevention
- Clamp or validate the -D value in cass-env/startup scripts
- Document allowed range wherever the flag is set
- Prefer removing the flag to using default rounds when unsure
When it happens
Trigger: Passing -Dcassandra.auth_bcrypt_gensalt_log2_rounds=<int> outside 4..30 (e.g. 2, 0, 50, negative) at JVM startup; a typo producing a non-parseable-then-clamped or extreme value.
Common situations: Operators tuning bcrypt cost for performance/security and overshooting the allowed range; copied startup scripts with aggressive low values; guessing the range instead of reading docs.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
Related errors
- %s has authorization enabled which requires %s to enable aut
- %s requires %s
- %s can't be used with %s
- %s does not support %s
- Failed to instantiate %s
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/e51639a67d93bcc8.
Report an issue: GitHub.