karatelabs/karate · error · RuntimeException
doc requires a string path or map with 'read' key, got:
Error message
doc requires a string path or map with 'read' key, got:
What it means
The `doc` keyword renders HTML (e.g. from a Markdown file) for embedding into reports. Its argument must be either a String path (wrapped internally as {read: path}) or a Map containing at least a 'read' key. Any other type (number, list, null-coerced object) cannot be processed and this error names the offending value.
Solutions
- Pass a plain string path: `doc classpath:doc.md` or a quoted path variable
- Pass a map with a 'read' key: `doc { read: '#(path)' }`
- print the value type before the doc step to verify
- Coerce with string concatenation if the value is a number/other scalar
Example fix
// before
* def meta = { file: 'notes.md' }
* doc meta
// after
* doc { read: '#(meta.file)' } Defensive patterns
Strategy: validation
Validate before calling
* if (!(docArg instanceof String || docArg.read)) karate.fail('doc arg must be string path or {read: ...} map') Type guard
function isValidDocArg(v) { return typeof v === 'string' || (v && typeof v === 'object' && 'read' in v); } Prevention
- Use the string path form for the common case
- Always include a 'read' key in the map form
- print value types when building doc args dynamically
When it happens
Trigger: `doc <expr>` where expr evaluates to a non-string/non-map value, e.g. a JSON array, integer, or a JS object that is not a plain Map; forgetting the map form: `doc { badKey: 'x' }` still passes the Map branch but doc itself will need 'read'.
Common situations: Using doc with a variable that was meant to be text but resolved to parsed JSON; copy-pasting examples and dropping the read key; dynamic doc paths built into lists.
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
- assert expression must return boolean:
- boot.ext(' '): does not implement io.karatelabs.core.Ext
- cache() second argument must be a function:
- call expression must resolve to a feature path:
- cannot set xpath on non-XML variable:
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/007d952fa0f6553e.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/StepExecutor.java:2993
} else {
expr = step.getText();
runtime.eval(expr, step);
}
}
@SuppressWarnings("unchecked")
private void executeDoc(Step step) {
String text = step.getText();
Object value = runtime.eval(wrapJsonLikeExpression(text));
// karate.doc() expects either a string path or a map with 'read' key
// Convert string to the expected format
String html;
if (value instanceof String path) {
html = runtime.getKarate().doc(Map.of("read", path));
} else if (value instanceof Map) {
html = runtime.getKarate().doc((Map<String, Object>) value);
} else {
throw new RuntimeException("doc requires a string path or map with 'read' key, got: " + value);
}
// Embed the rendered HTML in the step result for reports
if (html != null && !html.isEmpty()) {
LogContext.get().embed(html.getBytes(java.nio.charset.StandardCharsets.UTF_8), "text/html");
}
}
// ========== Config ==========
private void executeConfigure(Step step) {
String text = step.getText();
int eqIndex = StepUtils.findAssignmentOperator(text);
if (eqIndex < 0) {
throw new RuntimeException("configure requires '=' assignment: " + text);
}
String key = text.substring(0, eqIndex).trim();
String expr = text.substring(eqIndex + 1).trim();
if (expr.isEmpty() && step.getDocString() != null) {View on GitHub (pinned to a22eb90246)