# What is PEP 688?


[PEP 688: Making the buffer protocol accessible in Python](https://peps.python.org/pep-0688/) (Python 3.12) gives the buffer protocol a spelling in the type system, `collections.abc.Buffer`, and removes the typing special case that let `bytearray` and `memoryview` pass wherever `bytes` was expected.

If [mypy](https://pydevtools.com/handbook/reference/mypy.md) 2.0 started flagging `bytearray` arguments that checked clean for years, this PEP is why.

## Why did mypy start rejecting bytearray?

The original typing spec carved out a promotion: `bytearray` and `memoryview` were treated as assignable to `bytes`, on the theory that most code accepting binary data should accept all three. PEP 688 removed that promotion because it made the type system lie (a `bytes` annotation no longer guaranteed `bytes`).

mypy shipped the new behavior behind `--strict-bytes` in 1.15 and enabled it by default in mypy 2.0 (May 2026). The release notes state: "Per PEP 688, mypy no longer treats bytearray and memoryview values as assignable to the bytes type." Every mypy 2.0 user inherits this, with or without [strict mode](https://pydevtools.com/handbook/how-to/how-to-configure-mypy-strict-mode.md):

```console
$ mypy app.py
app.py:5: error: Argument 1 to "hexdump" has incompatible type "bytearray"; expected "bytes"  [arg-type]
app.py:6: error: Argument 1 to "hexdump" has incompatible type "memoryview[int]"; expected "bytes"  [arg-type]
```

`--no-strict-bytes` restores the old promotion while you migrate.

## Why was the old promotion unsound?

A `bytes` annotation promises an immutable, hashable value. `bytearray` is neither: a function that stores its argument can have it mutated out from under it, and one that uses it as a dict key gets `TypeError: unhashable type: 'bytearray'` at runtime. The promotion let both bugs through type checking.

## Annotate with Buffer instead

For functions that genuinely accept any binary data, annotate with `Buffer`, the protocol type this PEP added:

```python
from collections.abc import Buffer  # 3.12+; typing_extensions.Buffer for older versions

def hexdump(data: Buffer) -> str:
    return bytes(data).hex()
```

`bytes`, `bytearray`, and `memoryview` all satisfy `Buffer`, as does any C extension type implementing the buffer protocol (NumPy arrays, for example). The check works at runtime too: `issubclass(bytearray, Buffer)` returns `True`.

PEP 688 also lets pure-Python classes implement the protocol via `__buffer__` and `__release_buffer__` methods, which previously only C extensions could do.

## How do other checkers treat it?

[Pyright](https://pydevtools.com/handbook/reference/pyright.md) and [ty](https://pydevtools.com/handbook/reference/ty.md) already enforced PEP 688 semantics by default; Pyright's escape hatch is the `disableBytesTypePromotions` setting. mypy was the last major checker holding the promotion. A codebase upgrading to mypy 2.0, or [migrating between checkers](https://pydevtools.com/handbook/explanation/how-do-mypy-pyright-and-ty-compare.md), hits these errors as a batch.

## Learn More

- [PEP 688: Making the buffer protocol accessible in Python](https://peps.python.org/pep-0688/)
- [mypy 2.0 release notes](https://mypy-lang.blogspot.com/2026/05/mypy-20-relased.html)
- [collections.abc.Buffer documentation](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer)
- [What is PEP 561?](https://pydevtools.com/handbook/explanation/what-is-pep-561.md) covers the other typing PEP that surfaces as a surprising checker error
