{"record":{"id":"66fc07098ca5875b","repo":"opendataloader-project/opendataloader-pdf","slug":"page-image-fetcher-returned-null-for-page-s","errorCode":null,"errorMessage":"Page image fetcher returned null for page %s","messagePattern":"Page image fetcher returned null for page (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/DiskPageImageCache.java","lineNumber":61,"sourceCode":"    DiskPageImageCache(Path tempDir) {\n        this.tempDir = tempDir;\n    }\n\n    @Override\n    public BufferedImage getOrFetch(int pageIndex, PageImageFetcher fetcher) throws IOException {\n        Path file = tempDir.resolve(\"page-\" + pageIndex + \".png\");\n        if (Files.exists(file)) {\n            BufferedImage cached = ImageIO.read(file.toFile());\n            if (cached != null) {\n                return cached;\n            }\n            // Cached file is unreadable (corrupt or no ImageReader) — re-fetch.\n            LOGGER.log(Level.WARNING, \"Cached page image is unreadable, re-fetching: {0}\", file);\n            Files.deleteIfExists(file);\n        }\n        BufferedImage image = fetcher.fetch(pageIndex);\n        if (image == null) {\n            throw new IOException(\"Page image fetcher returned null for page \" + pageIndex);\n        }\n        if (!ImageIO.write(image, \"png\", file.toFile())) {\n            throw new IOException(\"No ImageIO writer accepted PNG output for page \" + pageIndex);\n        }\n        return image;\n    }\n\n    @Override\n    public void evict(int pageIndex) {\n        // no-op: keep on disk for potential re-read\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (!Files.exists(tempDir)) {\n            return;\n        }\n        try (DirectoryStream<Path> stream = Files.newDirectoryStream(tempDir)) {","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/DiskPageImageCache.java#L43-L79","documentation":"DiskPageImageCache.getOrFetch requires the supplied PageImageFetcher.fetch(pageIndex) to return a non-null BufferedImage so it can write the PNG to disk and hand it back. A null return means no image was produced for that page and the cache has nothing to persist or return, so it fails fast with IOException rather than writing an empty file or propagating a null downstream.","triggerScenarios":"A PageImageFetcher lambda passed to getOrFetch returns null for a page index. In the shipped pipeline the fetcher is HancomAIClient.fetchPageImage, which throws IOException instead of returning null, so this only fires for a custom/modified fetcher or a future code path that adds a null return.","commonSituations":"Writing a custom PageImageCache or fetcher for tests/stubs; a third-party image source that returns null on unsupported page indices; an OCR/render hook that swallows an error and yields null.","solutions":["Make the PageImageFetcher return a non-null BufferedImage for every requested page index","Throw IOException from the fetcher on failure instead of returning null","Validate the page-index range against the document before calling getOrFetch"],"exampleFix":"// before\nBufferedImage fetch(int i) {\n    if (outOfRange(i)) return null;\n    ...\n}\n// after\nBufferedImage fetch(int i) throws IOException {\n    if (outOfRange(i)) throw new IOException(\"page \" + i + \" out of range\");\n    ...\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// For a custom PageImageFetcher, validate the contract yourself\nPageImageFetcher safeFetcher = idx -> {\n    BufferedImage img = realFetcher.fetch(idx);\n    if (img == null) throw new IOException(\"no image for page \" + idx);\n    return img;\n};\nBufferedImage out = cache.getOrFetch(pageIndex, safeFetcher);","preventionTips":["Never return null from a PageImageFetcher — throw IOException on failure","Unit-test custom fetchers against the full page range","Prefer the shipped HancomAIClient.fetchPageImage which throws rather than returns null"],"tags":["hybrid","image-cache","null-check"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}