heibaiying/BigData-Notes · error · IllegalArgumentException
value structure should be longitude:latitude
Error message
value structure should be longitude:latitude
What it means
This IllegalArgumentException is thrown by the GEO branch of the Redis store bolt's process() logic (whitelisted from Storm's RedisStoreBolt) when the tuple value is not in the 'longitude:latitude' form required by Redis GEOADD. The code splits the value on ':' and expects exactly two parts, which are then parsed as doubles and passed to jedisCommand.geoadd(additionalKey, longitude, latitude, key). Any value without exactly one ':' separator fails before Redis is touched, is reported via collector.reportError(e), and the tuple is failed.
Source
Thrown at notes/Storm集成Redis详解.md:413
jedisCommand.hset(additionalKey, key, value);
break;
case SET:
jedisCommand.sadd(key, value);
break;
case SORTED_SET:
jedisCommand.zadd(additionalKey, Double.valueOf(value), key);
break;
case HYPER_LOG_LOG:
jedisCommand.pfadd(key, value);
break;
case GEO:
String[] array = value.split(":");
if (array.length != 2) {
throw new IllegalArgumentException("value structure should be longitude:latitude");
}
double longitude = Double.valueOf(array[0]);
double latitude = Double.valueOf(array[1]);
jedisCommand.geoadd(additionalKey, longitude, latitude, key);
break;
default:
throw new IllegalArgumentException("Cannot process such data type: " + dataType);
}
collector.ack(input);
} catch (Exception e) {
this.collector.reportError(e);
this.collector.fail(input);
} finally {
returnInstance(jedisCommand);
}View on GitHub (pinned to 3898939aca)
Solutions
- Fix the upstream producer so the value field is exactly "longitude:latitude" in decimal degrees, e.g. "116.407526:39.904030".
- If the upstream format is fixed and different, transform it before this bolt (add a preceding bolt that normalizes the value), or override process() to parse your format and call geoadd() yourself.
- If the data is not geographic at all, change the mapper's data type from GEO to the type that matches the data (STRING, HASH, SORTED_SET, ...).
- Sanitize in the mapper's getValueFromTuple(): validate and reformat there so bad values fail loudly at the boundary with a clearer message.
Example fix
// before: upstream spout emits collector.emit(new Values(cityName)); // value="Beijing" -> array.length==1 -> throws // after: upstream spout emits collector.emit(new Values(cityName, "116.407526:39.904030")); // "longitude:latitude" // (key=cityName, value="116.407526:39.904030" -> geoadd(additionalKey, 116.407526, 39.904030, cityName))
Defensive patterns
Strategy: validation
Validate before calling
String[] parts = value.split(":");
if (parts.length != 2 || !parts[0].matches("-?\\d+(\\.\\d+)?") || !parts[1].matches("-?\\d+(\\.\\d+)?")) {
throw new IllegalArgumentException("Expected longitude:latitude, got: " + value);
}
// safe to emit into the GEO-typed bolt Type guard
boolean isLongitudeLatitude(String value) {
if (value == null) return false;
String[] p = value.split(":");
if (p.length != 2) return false;
try {
double lon = Double.parseDouble(p[0]);
double lat = Double.parseDouble(p[1]);
return lon >= -180 && lon <= 180 && lat >= -90 && lat <= 90;
} catch (NumberFormatException e) {
return false;
}
} Try / catch
// In a normalizing bolt upstream of the GEO store bolt:
try {
collector.emit(new Values(key, lon + ":" + lat));
} catch (Exception e) {
collector.reportError(e);
collector.fail(input); // bad record: log and fail fast rather than retrying poisoned data
} Prevention
- Normalize coordinates to decimal-degree "longitude:latitude" at the spout/mapper boundary (getValueFromTuple), never inside the bolt.
- Validate with isLongitudeLatitude() before emitting; route bad records to a dead-letter stream instead of letting the bolt fail tuples.
- Pin the ':' delimiter in a shared constant used by both producer and consumer.
- Add contract tests on the spout's output format whenever the GEO bolt is part of the topology.
When it happens
Trigger: Declaring RedisDataTypeDescription.RedisDataType.GEO in the store mapper while upstream tuples emit values that: contain no ':' (e.g. "beijing"), contain extra ':' segments (e.g. "116.40:39.90:0"), have empty parts (":39.90", "116.40:"), or use a different delimiter (comma, space, e.g. "116.40,39.90" — note Double.valueOf would also throw NumberFormatException afterwards for malformed numbers). Only exactly-two-part values reach geoadd().
Common situations: Feeding GEO-typed bolts from spouts that emit plain text (e.g. a word-count stream reused for a GEO demo); changing the upstream data contract (delimiter switched from ':' to ',' or to a POJO/JSON) without updating the bolt; locale/format issues where coordinates arrive as DMS strings ("39°54'N") instead of decimal degrees; test data copy-pasted with the wrong separator.
Related errors
- Cannot process such data type for Count: ${dataType}
- Jedis configuration not found
- Cannot process such data type: ${dataType}
- Cannot process such data type for Count: ${dataType}
AI-assisted analysis of heibaiying/BigData-Notes@3898939aca (2026-08-14).
Data as JSON: /api/errors/f3f20c4127327607.
Report an issue: GitHub.