skylot/jadx · error · RuntimeException

Parse failed for option: ${option.name}, value: ${value}

Error message

Parse failed for option: ${option.name}, value: ${value}

What it means

Thrown by BasePluginOptionsBuilder.parseOption when the registered parser function for a plugin option throws any exception while converting the user-supplied string value. Jadx wraps the original exception in a RuntimeException so the plugin options builder can uniformly report parse failures with the option name and raw value. The cause chain preserves the underlying exception (e.g., NumberFormatException from Integer::parseInt).

Source

Thrown at jadx-core/src/main/java/jadx/api/plugins/options/impl/BasePluginOptionsBuilder.java:104

		for (OptionData<?> option : options) {
			parseOption(option, map.get(option.name));
		}
	}

	@Override
	public List<OptionDescription> getOptionsDescriptions() {
		return Collections.unmodifiableList(options);
	}

	private static <T> void parseOption(OptionData<T> option, @Nullable String value) {
		T parsedValue;
		if (value == null) {
			parsedValue = option.defaultValue;
		} else {
			try {
				parsedValue = option.getParser().apply(value);
			} catch (Exception e) {
				throw new RuntimeException("Parse failed for option: " + option.name + ", value: " + value, e);
			}
		}
		try {
			option.getSetter().accept(parsedValue);
		} catch (Exception e) {
			throw new RuntimeException("Setter invoke failed for option: " + option.name + ", value: " + parsedValue, e);
		}
	}

	private static boolean parseBoolOption(String name, String val) {
		String valLower = val.trim().toLowerCase(Locale.ROOT);
		if (valLower.equals("yes") || valLower.equals("true")) {
			return true;
		}
		if (valLower.equals("no") || valLower.equals("false")) {
			return false;
		}
		throw new IllegalArgumentException("Unknown value '" + val + "' for option '" + name + "', expect: 'yes' or 'no'");

View on GitHub (pinned to e738a26571)

Solutions

  1. Check the option's declared type and values (via getOptionsDescriptions) and supply a value that the option's parser accepts.
  2. For integer options, ensure the value is a valid base-10 integer with no surrounding text.
  3. For enum options, pass one of the documented enum constant names (case is handled by the default enumOption parser, but verify the specific plugin).
  4. If writing the plugin, make the custom parser more lenient or throw a descriptive IllegalArgumentException so the wrapped message is clear.

Example fix

// before
option("depth").parser(Integer::parseInt)
// invoked with: myplugin.depth=12x

// after (user fix): supply a valid integer
// myplugin.depth=12

// after (plugin author fix): validate before parse
option("depth").parser(s -> {
    try { return Integer.parseInt(s.trim()); }
    catch (NumberFormatException e) {
        throw new IllegalArgumentException("depth must be an integer, got: " + s);
    }
})
Defensive patterns

Strategy: validation

Validate before calling

// Check option description before parsing to validate user input
List<OptionDescription> descs = optionsBuilder.getOptionsDescriptions();
for (OptionDescription desc : descs) {
    if (desc.getName().equals(optionName)) {
        // For numeric options, verify the value is parseable
        if (desc.getType() == OptionType.NUMBER) {
            try { Integer.parseInt(userValue); }
            catch (NumberFormatException e) {
                throw new IllegalArgumentException(optionName + " requires an integer");
            }
        }
    }
}

Type guard

static boolean optionValueIsParsable(OptionDescription desc, String value) {
    if (value == null) return true;
    switch (desc.getType()) {
        case NUMBER:
            return value.matches("-?\\d+");
        case BOOLEAN:
            String lower = value.trim().toLowerCase(Locale.ROOT);
            return lower.equals("yes") || lower.equals("no")
                || lower.equals("true") || lower.equals("false");
        case STRING:
        default:
            return true;
    }
}

Try / catch

try {
    optionsBuilder.setOptions(userOptionsMap);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Parse failed for option:")) {
        LOG.error("Invalid option value: {}", e.getMessage());
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: A plugin registers an option via intOption(name) (whose parser is Integer::parseInt) and the user supplies a non-numeric string. Or a custom OptionBuilder.parser(Function) lambda throws on malformed input. The error fires inside setOptions(map) -> parseOption(option, value) when option.getParser().apply(value) raises.

Common situations: User passes --plugin-option myplugin.depth=abc to an integer option. A enumOption parser receives a value that does not match any enum constant (the valueOf call throws IllegalArgumentException). Locale-specific parsing (e.g., decimal separators) in a custom parser fails on unexpected input.

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/a9b08193a085e6ac. Report an issue: GitHub.