karatelabs/karate · error · RuntimeException

doc() requires 'read' key with template path

Error message

doc() requires 'read' key with template path

What it means

The doc() keyword renders an HTML template and sends it to a registered onDoc consumer (e.g. a report or driver). When called with an options Map, that Map must contain a 'read' key holding the template path; a missing/null 'read' throws this error.

Solutions

  1. Add the 'read' key with the template path: doc({ read: 'classpath:doc/template.html' })
  2. Verify the variable holding the path is not null at call time
  3. Check the doc() signature you're using — map form requires 'read', positional form takes the path as the first argument

Example fix

// before
* doc({ title: 'My Doc' })
// after
* doc({ read: 'classpath:docs/template.html', title: 'My Doc' })
Defensive patterns

Strategy: validation

Validate before calling

// before calling doc with a map
if (!opts || !opts.read) { throw 'doc options require read: <template path>'; }

Type guard

function hasRead(opts) { return opts != null && typeof opts.read === 'string' && opts.read.length > 0; }

Try / catch

try { karate.doc(opts); } catch (RuntimeException e) { if (e.getMessage().contains("requires 'read' key")) { log.error('doc options map must include read'); } throw e; }

Prevention

When it happens

Trigger: Calling doc with a map lacking 'read': doc({ title: 'x' }), or doc({ read: null }) — typically from a JS call site building the options object dynamically.

Common situations: Refactoring a doc() call from positional-args form to map form (or vice versa) and losing the 'read' key; a variable interpolating to null; typo like 'path:' instead of 'read:'.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/cdfc72e2fa910c2d. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/KarateJs.java:154

        if (_markup == null) {
            if (resourceResolver != null) {
                _markup = Markup.init(engine, resourceResolver);
            } else {
                _markup = Markup.init(engine, root.getPrefixedPath());
            }
        }
        return _markup;
    }

    /**
     * Renders an HTML template and returns the result.
     * Also sends to onDoc consumer if set.
     * Called by the 'doc' keyword in StepExecutor.
     */
    public String doc(Map<String, Object> options) {
        String read = (String) options.get("read");
        if (read == null) {
            throw new RuntimeException("doc() requires 'read' key with template path");
        }
        String html = markup().processPath(read, null);
        if (onDoc != null) {
            onDoc.accept(html);
        }
        return html;
    }

    @SuppressWarnings("unchecked")
    private JavaInvokable doc() {
        return args -> {
            if (onDoc == null) {
                logger.warn("doc() called, but no destination set");
                return null;
            }
            if (args.length == 0) {
                throw new RuntimeException("doc() needs at least one argument");
            }

View on GitHub (pinned to a22eb90246)