{"record":{"id":"6dc852f28e4436a7","repo":"elastic/elasticsearch","slug":"truncated-server-args-expected-bytes-got","errorCode":null,"errorMessage":"Truncated server args: expected {} bytes, got {}","messagePattern":"Truncated server args: expected (.+?) bytes, got (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"libs/server-launcher-common/src/main/java/org/elasticsearch/server/launcher/common/LaunchDescriptor.java","lineNumber":184,"sourceCode":"        return readFieldsFrom(in);\n    }\n\n    /**\n     * Reads descriptor fields without the magic number prefix.\n     * Subclasses can call this to read base fields from their own wire format.\n     */\n    protected static LaunchDescriptor readFieldsFrom(DataInputStream in) throws IOException {\n        String command = in.readUTF();\n        List<String> jvmOptions = readStringList(in);\n        List<String> jvmArgs = readStringList(in);\n        Map<String, String> environment = readStringMap(in);\n        String workingDir = in.readUTF();\n        String tempDir = in.readUTF();\n        boolean daemonize = in.readBoolean();\n        int serverArgsBytesLen = in.readInt();\n        byte[] serverArgsBytes = in.readNBytes(serverArgsBytesLen);\n        if (serverArgsBytes.length != serverArgsBytesLen) {\n            throw new IOException(\"Truncated server args: expected \" + serverArgsBytesLen + \" bytes, got \" + serverArgsBytes.length);\n        }\n\n        return new LaunchDescriptor(command, jvmOptions, jvmArgs, environment, workingDir, tempDir, daemonize, serverArgsBytes);\n    }\n\n    /**\n     * Checks the magic number from the stream and throws if it doesn't match.\n     */\n    protected static void checkMagic(DataInputStream in, int expectedMagic) throws IOException {\n        int magic = in.readInt();\n        if (magic != expectedMagic) {\n            throw new IOException(\"Invalid launch descriptor: bad magic number\");\n        }\n    }\n\n    /**\n     * Returns a human-readable representation of this descriptor in a section-based text format.\n     * Useful for debugging with the launcher's --dump flag.","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/server-launcher-common/src/main/java/org/elasticsearch/server/launcher/common/LaunchDescriptor.java#L166-L202","documentation":"Thrown by LaunchDescriptor.readFieldsFrom when DataInputStream.readNBytes(serverArgsBytesLen) returns fewer bytes than the declared length — i.e. the input ended mid-field. This indicates a truncated/cut-off launch descriptor file or stream: the header claimed N bytes of server args but EOF was reached first. IOException (checked).","triggerScenarios":"Reading a launch-descriptor file that was partially written (the launcher process died mid-write, or disk filled); passing a stream that was closed/severed before all bytes were sent; a length prefix that was corrupted to a huge value so readNBytes hits EOF; reading a file that was overwritten/truncated by a concurrent launcher.","commonSituations":"Server crash during descriptor serialization leaving a half-written file; inter-process pipe broken before the full payload was flushed; mismatched writer/reader versions where the writer writes fewer trailing bytes than the reader expects.","solutions":["Regenerate the launch descriptor file from the launcher (re-run the launch/bootstrap step) rather than retrying the read.","Ensure the writer flushes and fsyncs the descriptor before signaling the reader, and that the read happens after the write completes.","Verify writer and reader LaunchDescriptor versions match (same field order/length-prefix semantics).","If the length prefix looks implausibly large, treat the descriptor as corrupt and regenerate."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before reading, sanity-check the file size against the declared server args length.\nlong fileSize = Files.size(path);\n// read the length prefix in isolation if exposing a pre-check is feasible.","typeGuard":null,"tryCatchPattern":"try {\n    return LaunchDescriptor.readFrom(path);\n} catch (IOException e) {\n    throw new IOException(\"Launch descriptor at \" + path + \" is truncated or corrupted; regenerate it\", e);\n}","preventionTips":["fsync and flush the descriptor before signaling readers.","Match writer/reader LaunchDescriptor versions.","Regenerate the descriptor from the launcher rather than retrying the read."],"tags":["launcher","io","serialization","descriptor"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}