halo-dev/halo · error · IllegalArgumentException

Cannot convert key: {} to type: {}

Error message

Cannot convert key: {} to type: {}

What it means

Thrown as IllegalArgumentException by QueryVisitor.betweenQuery when the 'from' bound of a BETWEEN query cannot be converted by the registered ConversionService into the target index key type. Halo evaluates list/query filter expressions against in-memory indices, so each literal must be coercible to the index's declared Comparable key type.

Source

Thrown at application/src/main/java/run/halo/app/extension/index/query/QueryVisitor.java:221

        private <K extends Comparable<K>> Set<String> isNullQuery(String indexName, boolean negated) {
            var index = this.<K>getValueIndexQuery(indexName);
            if (negated) {
                return index.isNotNull();
            }
            return index.isNull();
        }

        private <K extends Comparable<K>> Set<String> betweenQuery(
                String indexName,
                Object fromKey,
                boolean fromInclusive,
                Object toKey,
                boolean toInclusive,
                boolean negated) {
            var index = this.<K>getValueIndexQuery(indexName);
            if (!conversionService.canConvert(fromKey.getClass(), index.getKeyType())) {
                throw new IllegalArgumentException(
                        "Cannot convert key: " + fromKey + " to type: " + index.getKeyType());
            }
            if (!conversionService.canConvert(toKey.getClass(), index.getKeyType())) {
                throw new IllegalArgumentException("Cannot convert key: " + toKey + " to type: " + index.getKeyType());
            }
            if (negated) {
                return index.notBetween(
                        conversionService.convert(fromKey, index.getKeyType()),
                        fromInclusive,
                        conversionService.convert(toKey, index.getKeyType()),
                        toInclusive);
            } else {
                return index.between(
                        conversionService.convert(fromKey, index.getKeyType()),
                        fromInclusive,
                        conversionService.convert(toKey, index.getKeyType()),
                        toInclusive);
            }

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Convert the from-bound to the index's key type on the caller side before building the query expression.
  2. Register a Converter<SourceType, KeyType> with the ConversionService used by the query layer.
  3. Verify the index name in the query actually points at the index with the expected key type.
  4. Align the literal format (e.g. ISO-8601 for dates, decimal string for numbers) with what the converter expects.

Example fix

// before
query.between("creationTimestamp", "2024-01-01", ...); // String vs date index

// after
query.between("creationTimestamp", Instant.parse("2024-01-01T00:00:00Z"), ...);
Defensive patterns

Strategy: validation

Validate before calling

Class<?> keyType = valueIndexQuery.getKeyType();
if (!conversionService.canConvert(fromBound.getClass(), keyType)) {
    throw new IllegalArgumentException("BETWEEN from-bound not convertible to " + keyType);
}

Type guard

static boolean boundConvertible(ConversionService cs, Object bound, Class<?> keyType) {
    return bound != null && cs.canConvert(bound.getClass(), keyType);
}

Try / catch

try {
    results = visitor.betweenQuery(idx, fromBound, true, toBound, true, false);
} catch (IllegalArgumentException e) {
    // tell the caller the bound type is incompatible; suggest the index key type
    throw new ServerWebInputException("Invalid BETWEEN bound type for index " + idx, null, e);
}

Prevention

When it happens

Trigger: A ListOptions/field-selector query uses a BETWEEN operator whose lower bound literal type is incompatible with the index key type, e.g. querying a numeric/date index with a String bound that has no registered converter, or vice-versa.

Common situations: Passing raw String params from an HTTP query string against a numeric or temporal index; querying an index whose key type changed after a schema migration; a missing/removed ConversionService converter for a custom key type.

Related errors


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/414ffa2704862b87. Report an issue: GitHub.