{"record":{"id":"fc7c91f08a9e94da","repo":"elastic/elasticsearch","slug":"failed-to-skip-bytes-while-reading","errorCode":null,"errorMessage":"failed to skip [{}] bytes while reading [{}]","messagePattern":"failed to skip \\[(.+?)\\] bytes while reading \\[(.+?)\\]","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/MMDBUtil.java","lineNumber":48,"sourceCode":"    private static final int BUFFER_SIZE = 2048;\n\n    /**\n     * Read the database type from the database. We do this manually instead of relying on the built-in mechanism to avoid reading the\n     * entire database into memory merely to read the type. This is especially important to maintain on master nodes where pipelines are\n     * validated. If we read the entire database into memory, we could potentially run into low-memory constraints on such nodes where\n     * loading this data would otherwise be wasteful if they are not also ingest nodes.\n     *\n     * @return the database type\n     * @throws IOException if an I/O exception occurs reading the database type\n     */\n    public static String getDatabaseType(final Path database) throws IOException {\n        final long fileSize = Files.size(database);\n        try (InputStream in = Files.newInputStream(database)) {\n            // read the last BUFFER_SIZE bytes (or the fileSize, whichever is smaller)\n            final long skip = fileSize > BUFFER_SIZE ? fileSize - BUFFER_SIZE : 0;\n            final long skipped = in.skip(skip);\n            if (skipped != skip) {\n                throw new IOException(\"failed to skip [\" + skip + \"] bytes while reading [\" + database + \"]\");\n            }\n            final byte[] tail = new byte[BUFFER_SIZE];\n            int read = 0;\n            int actualBytesRead;\n            do {\n                actualBytesRead = in.read(tail, read, BUFFER_SIZE - read);\n                read += actualBytesRead;\n            } while (actualBytesRead > 0);\n\n            // find the database_type header\n            int metadataOffset = -1;\n            int markerOffset = 0;\n            for (int i = 0; i < tail.length; i++) {\n                byte b = tail[i];\n\n                if (b == DATABASE_TYPE_MARKER[markerOffset]) {\n                    markerOffset++;\n                } else {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/MMDBUtil.java#L30-L66","documentation":"Thrown by MMDBUtil.getDatabaseType when InputStream.skip does not skip the exact number of bytes requested (the last BUFFER_SIZE bytes of the file). Per the InputStream contract, skip may return fewer bytes than requested; here any shortfall is treated as a read failure of the mmdb tail. IOException propagates to the caller that reads database type for lookup wiring.","triggerScenarios":"getDatabaseType(path): fileSize > BUFFER_SIZE -> skip = fileSize - BUFFER_SIZE; skipped = in.skip(skip); skipped != skip -> throw.","commonSituations":"Very small or empty mmdb file where skip semantics behave oddly; a non-mmdb file fed to the geoip loader; a corrupt or truncated download; a special filesystem whose InputStream.skip under-delivers.","solutions":["Verify the file is a valid mmdb and is non-empty (check size and magic).","Re-download the database in case of truncation.","Ensure the file is fully written/flushed before getDatabaseType reads it.","If reading from a custom FileSystem, use a stream whose skip is reliable or read-and-discard instead."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"void assertMmdbReadable(Path p) throws IOException {\n    if (Files.size(p) == 0) throw new IOException(\"empty mmdb: \" + p);\n    try (InputStream in = Files.newInputStream(p)) {\n        long skipped = 0, target = Math.max(0, Files.size(p) - BUFFER_SIZE);\n        while (skipped < target) {\n            long s = in.skip(target - skipped);\n            if (s <= 0) throw new IOException(\"cannot skip to mmdb tail: \" + p);\n            skipped += s;\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    String type = MMDBUtil.getDatabaseType(path);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"failed to skip\")) {\n        // re-download or supply a fully-written valid mmdb\n    } else throw e;\n}","preventionTips":["Validate the mmdb is non-empty and fully written before reading its type.","Re-download on truncation rather than retrying the same file.","Use reliable streams (regular FS) for skip; avoid skip-unreliable custom FS.","Confirm gunzip was performed if the source was gzipped."],"tags":["geoip","mmdb","filesystem","io","data-integrity"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}