{"id":1969,"library":"construct","title":"construct Binary Data Parser","description":"construct is a powerful declarative symmetric parser/builder for binary data, supporting Python 3.6+. It allows you to define the structure of binary data using Python objects and then parse or build data according to that structure. The current version is 2.10.70, and it maintains a fairly active release cadence, often releasing minor fixes and improvements.","status":"active","version":"2.10.70","language":"python","source_language":"en","source_url":"https://github.com/construct/construct","tags":["binary data","parser","builder","serialization","deserialization","protocol","struct"],"install":[{"cmd":"pip install construct","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"Old import path for construct versions prior to 2.5/2.6. Modern construct uses top-level imports.","wrong":"from construct.core import Struct","symbol":"Struct","correct":"from construct import Struct"},{"symbol":"Int8ub","correct":"from construct import Int8ub"},{"symbol":"Bytes","correct":"from construct import Bytes"},{"symbol":"Array","correct":"from construct import Array"},{"symbol":"GreedyRange","correct":"from construct import GreedyRange"},{"symbol":"StreamError","correct":"from construct import StreamError"}],"quickstart":{"code":"from construct import Struct, Int8ub, Bytes, Array, GreedyRange, StreamError\n\n# Define a simple binary structure\n# A header, an array of 8-bit unsigned integers, and a variable-length data block\npacket_struct = Struct(\n    \"header\" / Bytes(4), # 4-byte header\n    \"count\" / Int8ub,    # 1-byte count of following integers\n    \"data\" / Array(lambda ctx: ctx.count, Int8ub), # Array of 'count' integers\n    \"payload\" / GreedyRange(Int8ub) # Remaining bytes as a list of integers\n)\n\n# Example data to build\nmy_data = {\n    \"header\": b\"\\xde\\xad\\xbe\\xef\",\n    \"count\": 3,\n    \"data\": [10, 20, 30],\n    \"payload\": [1, 2, 3, 4, 5]\n}\n\n# Build binary data from Python object\nbuilt_binary = packet_struct.build(my_data)\nprint(f\"Built binary: {built_binary.hex()}\")\n\n# Parse binary data into Python object\n# Using a different example binary for parsing\nbinary_to_parse = b\"\\xaa\\xbb\\xcc\\xdd\\x02\\x01\\x02\\xff\\xee\\xdd\"\n\ntry:\n    parsed_object = packet_struct.parse(binary_to_parse)\n    print(f\"Parsed object: {parsed_object}\")\n\n    # Accessing fields\n    print(f\"Parsed header: {parsed_object.header.hex()}\")\n    print(f\"Parsed data: {parsed_object.data}\")\nexcept StreamError as e:\n    print(f\"Error parsing data: {e}\")","lang":"python","description":"This quickstart demonstrates how to define a `Struct` using various constructors like `Bytes`, `Int8ub`, `Array`, and `GreedyRange`. It shows how to use lambda functions within a structure definition to refer to previously parsed fields (e.g., `ctx.count`). Finally, it illustrates building Python objects into binary data and parsing binary data back into Python objects, including basic error handling."},"warnings":[{"fix":"Migrate your code to the modern construct API (2.8+ is recommended). This will likely involve a complete rewrite of your structure definitions and parsing/building logic. Refer to the official construct documentation for the current API.","message":"Major API overhaul occurred between construct 2.0 and 2.5/2.6. This was a near-complete rewrite, deprecating and removing many constructs (e.g., `Buffer`, `BitStruct`), changing import paths (`construct.core`), and modifying core behaviors. Code written for construct 2.0 is highly unlikely to work with 2.5+.","severity":"breaking","affected_versions":"< 2.5"},{"fix":"Review the changelog for versions 2.8 and 2.9. Update `Subconstruct` usage to directly use the base construct, rename `RepeatUntil` to `GreedyRange`, and adjust conditional error handling if `Context.error_when` was used.","message":"Breaking changes were introduced in versions 2.8 and 2.9. Notably, `Subconstruct` was removed in 2.8 (use `Construct` directly), `RepeatUntil` was renamed to `GreedyRange`, and `Context.error_when` behavior changed slightly in 2.9.","severity":"breaking","affected_versions":">= 2.8"},{"fix":"If you need to reuse a construct with different parameters or ensure isolation, create a new instance each time, or use `construct.deep_copy` if you're modifying a complex, nested structure and need a true independent copy.","message":"Construct objects (e.g., `Struct`, `Array`) are often mutable. If you create an instance of a construct and then modify its internal properties or reuse it in different contexts without care, you might encounter unexpected side effects due to shared state.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Thoroughly understand the `Context` object and how `this` (or `ctx`) dynamically refers to the current parsing/building context. Debug with `construct.Probe` to inspect the context at various points in your structure definition. Ensure fields are defined before they are referenced via `this`.","message":"The `this` (or `ctx`) variable, used for accessing context and previously parsed fields within `lambda` functions or methods, can be a source of confusion. Misunderstanding its scope or when certain fields become available can lead to errors.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-24T04:07:38.035Z","next_check":"2026-07-08T00:00:00.000Z","problems":[{"fix":"Install the library using pip: `pip install construct`.","cause":"The 'construct' library is not installed in the Python environment, or the environment where the code is being run does not have access to the installed package.","error":"ModuleNotFoundError: No module named 'construct'"},{"fix":"Ensure the input binary data provided to the `parse()` method is complete and matches the structure defined by the construct. You might need to check the source of your binary data or adjust the construct's definition if the data length is variable.","cause":"This error occurs when the parsing operation expects to read a certain number of bytes from the input stream, but the stream ends prematurely or contains fewer bytes than the defined construct requires.","error":"construct.core.StreamError: could not read enough bytes"},{"fix":"Verify the binary data being parsed against the expected constant value defined in the `Const` construct. If the data is correct and the `Const` definition is incorrect, update the `Const` value. If the data is faulty, correct the data source.","cause":"A `Const` field in the construct definition enforces that a specific byte sequence (or value) must be present at that point in the stream. This error means the data being parsed does not match the expected constant value.","error":"construct.core.ConstError: expected b'VALUE_A' but parsed b'VALUE_B'"},{"fix":"Explicitly convert the `bytes` object to an integer using methods like `int.from_bytes(byte_object, byteorder)` with the correct byte order, or access individual bytes as integers (e.g., `byte_object[0]`). Conversely, convert integers to bytes using `int.to_bytes()` when building.","cause":"This common Python error often arises when working with `construct` because you are attempting to use a `bytes` object (which `construct` frequently returns) in a context where an integer value is expected, or vice-versa, without proper conversion.","error":"TypeError: 'bytes' object cannot be interpreted as an integer"},{"fix":"If the size depends on a context value, ensure that the necessary key is present in the context dictionary when calling `sizeof()` or when building. For dynamically sized constructs, `sizeof()` might not be determinable, and you may need to rely on parsing or building to calculate the actual size.","cause":"This error is raised when the `sizeof()` method of a construct cannot determine its size upfront, often because it depends on a value from the context dictionary that is not available or because the construct has a variable size that cannot be computed statically.","error":"construct.core.SizeofError: SizeofError"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"install_checks":{"last_tested":"2026-04-24","tag":null,"tag_description":null,"results":[{"runtime":"python:3.10-alpine","variant":"default","exit_code":0,"import_time_s":0.13,"mem_mb":5.5,"disk_size":"18.4M"},{"runtime":"python:3.10-slim","variant":"default","exit_code":0,"import_time_s":0.09,"mem_mb":5.5,"disk_size":"19M"},{"runtime":"python:3.11-alpine","variant":"default","exit_code":0,"import_time_s":0.21,"mem_mb":5.6,"disk_size":"20.4M"},{"runtime":"python:3.11-slim","variant":"default","exit_code":0,"import_time_s":0.15,"mem_mb":5.6,"disk_size":"21M"},{"runtime":"python:3.12-alpine","variant":"default","exit_code":0,"import_time_s":0.2,"mem_mb":5.6,"disk_size":"12.2M"},{"runtime":"python:3.12-slim","variant":"default","exit_code":0,"import_time_s":0.19,"mem_mb":5.6,"disk_size":"13M"},{"runtime":"python:3.13-alpine","variant":"default","exit_code":0,"import_time_s":0.2,"mem_mb":6.7,"disk_size":"11.9M"},{"runtime":"python:3.13-slim","variant":"default","exit_code":0,"import_time_s":0.18,"mem_mb":6.5,"disk_size":"12M"},{"runtime":"python:3.9-alpine","variant":"default","exit_code":0,"import_time_s":0.13,"mem_mb":5.8,"disk_size":"17.9M"},{"runtime":"python:3.9-slim","variant":"default","exit_code":0,"import_time_s":0.11,"mem_mb":5.8,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-25","tag":null,"tag_description":null,"results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}