shwenzhang/AndResGuard · error · OptionsException
( ) must be a decimal number
Error message
<valueDescription> (<mLastOptionOriginalForm>) must be a decimal number: <value>
What it means
An option whose value must be an integer (parsed via Integer.parseInt) received a non-decimal value. The parser first fetched the required value successfully, then failed converting it, reporting the offending option, its original form, and the raw value. Typical of options like --min-sdk-version or --v1-signing-scheme variants taking numeric input.
Solutions
- Replace the value with a plain decimal integer (Android API level), e.g. `--min-sdk-version 24` instead of `--min-sdk-version 7.0`.
- Trim whitespace and hidden characters from the value, especially in shell scripts: `"${VAR//[[:space:]]/}"`.
- Convert hex or version strings to decimal API levels before passing them.
- Check which option the message names — it points at the exact flag receiving the bad value.
Example fix
// before apksigner sign --min-sdk-version 7.0 --out app.apk in.apk // after apksigner sign --min-sdk-version 24 --out app.apk in.apk
Defensive patterns
Strategy: validation
Validate before calling
static String requireDecimal(String option, String value) {
if (value == null || !value.matches("-?\\d+")) {
throw new IllegalArgumentException(option + " must be a decimal integer (got: " + value + ")");
}
return value.trim();
}
// usage before building the command line:
String minSdk = requireDecimal("--min-sdk-version", System.getenv("MIN_SDK")); Try / catch
try {
apksignerSign(args);
} catch (OptionsException e) {
if (e.getMessage().contains("must be a decimal number")) {
System.err.println("Bad numeric flag: " + e.getMessage()
+ " — pass Android API levels as plain integers (e.g. 24, not 7.0).");
}
throw e;
} Prevention
- Pass Android API levels (24, 28, 30) rather than version names (7.0, 11).
- Sanitize numeric env variables: trim whitespace and strip non-digits before use.
- Avoid hex notation (0x18) for numeric flags.
- Validate script variables with a regex ^-?\d+$ before interpolation.
- Keep numeric values unquoted-only when the value itself contains no stray characters.
When it happens
Trigger: Calling `apksigner sign --min-sdk-version 4.2 ...` or passing values with spaces, plus signs in unexpected places, hex notation (`0x18`), or an empty/non-numeric value where an int option is expected.
Common situations: Copying Android API level as a version string ("7.0") instead of the numeric API level (24); typos like `24 ` with trailing characters; localization or shell quoting introducing invisible characters; scripts interpolating non-numeric variables into numeric flags.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Missing APK
- Unexpected parameter(s) after APK (<params[1]>)
- --ks and --key may not be specified at the same time
- --ks and --cert may not be specified at the same time
- KeyStore (--ks) or private key file (--key) must be…
AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12).
Data as JSON: /api/errors/4b07c0d6385d624c.
Report an issue: GitHub.
Appendix: source
Thrown at AndResGuard-core/src/main/java/apksigner/OptionsParser.java:128
String param = mParams[mIndex];
if ("--".equals(param)) {
// End of options marker
throw new OptionsException(valueDescription + " missing after " + mLastOptionOriginalForm);
}
mIndex++;
return param;
}
/**
* Returns the value of the current numeric option, throwing an exception if the value is
* missing or is not numeric.
*/
public int getRequiredIntValue(String valueDescription) throws OptionsException {
String value = getRequiredValue(valueDescription);
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new OptionsException(valueDescription
+ " ("
+ mLastOptionOriginalForm
+ ") must be a decimal number: "
+ value);
}
}
/**
* Gets the value of the current boolean option. Boolean options are not required to have
* explicitly specified values.
*/
public boolean getOptionalBooleanValue(boolean defaultValue) throws OptionsException {
if (mLastOptionValue != null) {
// --option=value form
String stringValue = mLastOptionValue;
mLastOptionValue = null;
if ("true".equals(stringValue)) {
return true;View on GitHub (pinned to e4df245d82)