karatelabs/karate · error · RuntimeException
toCsv() argument must be a list of maps, got
Error message
toCsv() argument must be a list of maps, got: {className} What it means
karate.toCsv() converts a list of Maps into CSV text via DataUtils.toCsv. The library throws this error when the first argument is not a List; the concrete class of the offending value is appended to the message. Null input and empty lists are explicitly tolerated (they return an empty string), so only a wrong-typed non-null argument triggers this.
Solutions
- Wrap a single map in a list: karate.toCsv([myMap]).
- Ensure each element is a Map (JSON object); convert arrays or other shapes first.
- Verify the data source actually returns a list (e.g. response is an array of objects, not an object).
Example fix
// before karate.toCsv(response) // response is a single object // after karate.toCsv([response])
Defensive patterns
Strategy: type-guard
Validate before calling
if (rows != null && !Array.isArray(rows)) { throw new Error('toCsv() expects a list of maps; got: ' + typeof rows) }
if (Array.isArray(rows) && rows.some(r => r == null || typeof r !== 'object' || Array.isArray(r))) { throw new Error('toCsv() rows must all be maps') } Type guard
function isListOfMaps(v) { return Array.isArray(v) && v.every(r => r != null && typeof r === 'object' && !Array.isArray(r)) } Try / catch
try { var csv = karate.toCsv(rows) } catch (e) { if (('' + e).indexOf('must be a list of maps') >= 0) { csv = karate.toCsv([rows]) } else { throw e } } Prevention
- Wrap single objects in an array before calling toCsv
- Validate API responses are arrays of objects before CSV export
- Remember null and empty list are safe (return empty string) — only wrong non-null types throw
When it happens
Trigger: karate.toCsv(singleMap) instead of a list of maps; passing a Java array, a JSON string, or the result of a query that returned an object rather than a list.
Common situations: Exporting API response data to CSV where the response is a single JSON object not wrapped in an array; passing an ArrayList-like custom type; forgetting that toCsv expects List<Map<String,Object>> rows.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- channel() needs a type argument, e.g…
- get() needs at least one argument
- params() needs a map argument
- read() needs at least one argument
- readAsBytes() needs at least one argument
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/6d66767f2ebfabf9.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/KarateJsUtils.java:545
String className = args[1].toString();
// Convert to JSON string and deserialize to the target class
String jsonString = Json.of(obj).toString();
return Json.fromJson(jsonString, className);
};
}
/**
* Convert a list of maps to CSV string.
* Usage: karate.toCsv([{a:1,b:2},{a:3,b:4}]) => "a,b\n1,2\n3,4\n"
*/
@SuppressWarnings("unchecked")
static JavaInvokable toCsv() {
return args -> {
if (args.length == 0 || args[0] == null) {
return "";
}
if (!(args[0] instanceof List)) {
throw new RuntimeException("toCsv() argument must be a list of maps, got: " + args[0].getClass().getName());
}
List<Map<String, Object>> list = (List<Map<String, Object>>) args[0];
if (list.isEmpty()) {
return "";
}
return DataUtils.toCsv(list);
};
}
@SuppressWarnings("unchecked")
static JavaInvokable toBytes() {
return args -> {
if (args.length < 1) {
throw new RuntimeException("toBytes() needs one argument: a list of numbers");
}
Object arg = args[0];
if (arg instanceof byte[]) {
return arg; // already bytesView on GitHub (pinned to a22eb90246)