diff --git a/qiskit/qpy/interface.py b/qiskit/qpy/interface.py index 9886160dacc0..f4a77ec14598 100644 --- a/qiskit/qpy/interface.py +++ b/qiskit/qpy/interface.py @@ -231,6 +231,12 @@ def load( version = struct.unpack("!6sB", file_obj.read(7))[1] file_obj.seek(0) + if version > common.QPY_VERSION: + raise QiskitError( + f"The QPY format version being read, {version}, isn't supported by " + "this Qiskit version. Please upgrade your version of Qiskit to load this QPY payload" + ) + if version < 10: data = formats.FILE_HEADER._make( struct.unpack( diff --git a/releasenotes/notes/fix-error-message-qpy-version-cf0763da22ce2224.yaml b/releasenotes/notes/fix-error-message-qpy-version-cf0763da22ce2224.yaml new file mode 100644 index 000000000000..67690c011126 --- /dev/null +++ b/releasenotes/notes/fix-error-message-qpy-version-cf0763da22ce2224.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed an issue with :func:`.qpy.load` when attempting to load a QPY format + version that is not supported by this version of Qiskit it will now display + a descriptive error message. Previously, it would raise an internal error + because of the incompatibility between the formats which was difficult to + debug. If the QPY format verison is not supported that indicates the Qiskit + version will need to be upgraded to read the QPY payload. diff --git a/test/python/qpy/test_circuit_load_from_qpy.py b/test/python/qpy/test_circuit_load_from_qpy.py index 3684e8aacfe6..ba6aeb81f290 100644 --- a/test/python/qpy/test_circuit_load_from_qpy.py +++ b/test/python/qpy/test_circuit_load_from_qpy.py @@ -13,12 +13,15 @@ """Test cases for the schedule block qpy loading and saving.""" import io +import struct from ddt import ddt, data from qiskit.circuit import QuantumCircuit, QuantumRegister, Qubit from qiskit.providers.fake_provider import FakeHanoi, FakeSherbrooke -from qiskit.qpy import dump, load +from qiskit.exceptions import QiskitError +from qiskit.qpy import dump, load, formats +from qiskit.qpy.common import QPY_VERSION from qiskit.test import QiskitTestCase from qiskit.transpiler import PassManager, TranspileLayout from qiskit.transpiler import passes @@ -71,6 +74,20 @@ def test_rzx_calibration_echo(self, angle): self.assert_roundtrip_equal(rzx_qc) +class TestVersions(QpyCircuitTestCase): + """Test version handling in qpy.""" + + def test_invalid_qpy_version(self): + """Test a descriptive exception is raised if QPY version is too new.""" + with io.BytesIO() as buf: + buf.write( + struct.pack(formats.FILE_HEADER_PACK, b"QISKIT", QPY_VERSION + 4, 42, 42, 1, 2) + ) + buf.seek(0) + with self.assertRaisesRegex(QiskitError, str(QPY_VERSION + 4)): + load(buf) + + @ddt class TestLayout(QpyCircuitTestCase): """Test circuit serialization for layout preservation."""