apache/cassandra · error · IOException

Unsupported ballot file version

Error message

Unsupported ballot file version: ${version}

What it means

PaxosBallotTracker persists high/low paxos ballots to a per-directory ballot file stamped with a FILE_VERSION. On load it throws IOException 'Unsupported ballot file version' when the file's version integer differs from the version this build writes — typically a file from a different Cassandra version or a corrupt/garbage first 4 bytes.

Solutions

  1. Stop the node and delete the ballot file (it is rebuilt from current paxos state; safe while no in-flight CAS relies on it — prefer deleting only when the directory is for a dropped/unsupported state)
  2. Confirm the running Cassandra version matches the version that wrote the files; complete a rolling upgrade/downgrade consistently
  3. Check disk/filesystem health if the version bytes look corrupted
  4. If caused by downgrade, use the officially supported downgrade procedure which handles state files

Example fix

// before
cassandra$ cp -r /old/data /data   # old-version ballot files mixed in
// after
cassandra$ rm /data/*/paxos_ballot*   # or matching ballot tracker files
$ .build/build-jars.sh -s && restart node
Defensive patterns

Strategy: validation

Validate before calling

// check the ballot file's version int before starting Cassandra
try (DataInputStream in = new DataInputStream(new FileInputStream(ballotFile))) {
    int v = Integer.reverseBytes(in.readInt());
    if (v != expectedFileVersion) { /* move file aside or confirm upgrade/downgrade path */ }
}

Try / catch

try { PaxosBallotTracker.load(dir); } catch (IOException e) { if (e.getMessage().startsWith("Unsupported ballot file version")) { /* remove/rotate file, reload */ } throw e; }

Prevention

When it happens

Trigger: Downgrading or upgrading Cassandra across versions that changed the ballot file format; a truncated or zero-filled ballot file left by a crash; the file being written by a different (patched) implementation.

Common situations: Rolling upgrades/downgrades where old ballot files remain in the data directories; restoring data dirs from backups taken with a different version; disk corruption.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/51e1397223702d21. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/service/paxos/uncommitted/PaxosBallotTracker.java:105

    {
        logger.info("truncating paxos ballot metadata in {}", directory);
        deleteIfExists(new File(directory, TMP_FNAME));
        deleteIfExists(new File(directory, FNAME));
    }

    public static PaxosBallotTracker load(File directory) throws IOException
    {
        deleteIfExists(new File(directory, TMP_FNAME));

        File file = new File(directory, FNAME);
        if (!file.exists())
            return new PaxosBallotTracker(directory, Ballot.none(), Ballot.none());

        try (RandomAccessReader reader = RandomAccessReader.open(file))
        {
            int version = reader.readInt();
            if (version != FILE_VERSION)
                throw new IOException("Unsupported ballot file version: " + version);

            byte[] bytes = new byte[16];
            CRC32 crc = crc32();
            Ballot highBallot = deserializeBallot(reader, crc, bytes);
            Ballot lowBallot = deserializeBallot(reader, crc, bytes);
            int checksum = Integer.reverseBytes(reader.readInt());
            if (!reader.isEOF() || (int) crc.getValue() != checksum)
                throw new IOException("Ballot file corrupted");

            return new PaxosBallotTracker(directory, highBallot, lowBallot);
        }
    }

    private static void deleteIfExists(File file)
    {
        if (file.exists())
            file.delete();
    }

View on GitHub (pinned to 88fd0f6a0e)