Skip to content

qpy.dump fails with gzip files in QPY v16 due to unsupported backward seek #15157

@Siddharthgolecha

Description

@Siddharthgolecha

Environment

  • Qiskit version: 2.2
  • Python version: 2.2.0 (QPY 16)
  • Operating system: Any (Linux/macOS/Windows)

What is happening?

In QPY version 16 (Qiskit ≥ 2.2.0), qpy.dump() introduces a circuit offset table that requires seeking back to fill offsets after writing the circuit data. This causes an OSError: Negative seek in write mode when the output stream is a gzip.GzipFile opened in write mode, because gzip only supports forward seeks.

This is probably caused by #14953 .

How can we reproduce the issue?

import gzip
from qiskit import QuantumCircuit, qpy

qc = QuantumCircuit(2)
qc.h(0); qc.h(1)

with gzip.open("circuit.qpy.gz", "wb") as f:
    qpy.dump(qc, f)

Error:
OSError: Negative seek in write mode

The qpy.dump() checks only file_obj.seekable() to decide whether to use the “fast path” that performs in-place offset table writing. However, gzip.GzipFile reports seekable() == True yet does not support backward seeks, triggering the exception.

What should happen?

qpy.dump() should successfully write QPY v16 data to any binary writable file-like object, including compressed streams like gzip.GzipFile, without requiring random-access seeking.

Specifically:

  • The function should automatically detect when a stream cannot perform backward seeks (e.g., gzip write mode) and transparently fall back to a buffered approach.

  • Users should be able to do:

    import gzip
    from qiskit import QuantumCircuit, qpy
    
    qc = QuantumCircuit(2)
    qc.h(0)
    qc.h(1)
    
    with gzip.open("circuit.qpy.gz", "wb") as f:
        qpy.dump(qc, f)

    …and expect it to complete without error and produce a valid .qpy.gz file readable by:

    with gzip.open("circuit.qpy.gz", "rb") as f:
        qpy.load(f)

In short, QPY serialization should be stream-agnostic, working seamlessly with both seekable files (e.g., disk files) and non-seekable or partially seekable streams (e.g., gzip, sockets, pipes).

Any suggestions?

I added a small runtime probe to detect if the stream truly supports backward seeks. If not, fall back to the buffered write path (BytesIO) used for non-seekable streams.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions