karatelabs/karate · error · IllegalStateException

store has been closed

Error message

store has been closed

What it means

DiskBackedList.get() throws this IllegalStateException when the list's backing store has already been closed via close(). After close, the temp file and RandomAccessFile handles are released, so reads are rejected explicitly rather than failing obscurely. This is a use-after-close guard.

Solutions

  1. Do not close the list until all reads (get/iterator) are complete
  2. If you need the data after close, copy it into a regular List before closing
  3. Restructure so the consumer owns the list lifecycle (close where it was created)
  4. Guard concurrent access: ensure close happens only after all reader threads finish

Example fix

// before
try (DiskBackedList list = new DiskBackedList(...)) { fill(list); }
return list; // closed!
// after
DiskBackedList list = new DiskBackedList(...);
fill(list);
return list; // caller closes
Defensive patterns

Strategy: try-catch

Validate before calling

if (list instanceof DiskBackedList) {
  // cannot query closed state publicly; ensure close happens after use
  useList(list);
  ((DiskBackedList) list).close();
}

Type guard

boolean isClosed(DiskBackedList l) { try { l.size(); return false; } catch (IllegalStateException e) { return true; } }

Try / catch

try { return list.get(i); } catch (IllegalStateException e) { if (e.getMessage().equals("store has been closed")) throw new IllegalStateException("read after close; keep list open until consumers finish", e); throw e; }

Prevention

When it happens

Trigger: Calling get(index) on a DiskBackedList after calling close(); using a list that was closed by a try-with-resources block or shutdown hook; sharing the list across threads where one thread closes while another reads.

Common situations: Returning a DiskBackedList from a method that used try-with-resources; closing in a finally block then iterating later; lifecycle bugs in large-result-set handling where results are lazily read from disk.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/match/DiskBackedList.java:179

        return JSONValue.toJSONString(item);
    }

    private static Object deserializeItem(String json) {
        if (json == null || json.isEmpty() || "null".equals(json)) {
            return null;
        }
        return JSONValue.parse(json);
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public Object get(int index) {
        if (closed) {
            throw new IllegalStateException("store has been closed");
        }
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("index: " + index + ", size: " + size);
        }
        try {
            if (raf == null) {
                raf = new RandomAccessFile(tempFile, "r");
            }
            long offset = lineOffsets.get(index);
            raf.seek(offset);
            String line = raf.readLine();
            return deserializeItem(line);
        } catch (IOException e) {
            throw new RuntimeException("failed to read item at index " + index, e);
        }
    }

    @Override

View on GitHub (pinned to a22eb90246)