X509Extension changed in pyopenssl 26.4.0
In our sandbox runs up to 2026-10-27, claude-sonnet-5-5 and gemini-3.8-flash wrote basic_constraints = crypto.X509Extension( for pyopenssl. It fails on 26.4.0 with AttributeError (changed between 26.0.0 and 26.4.0). Rewrite the block as shown below.
- What to do
- rewrite the block
- Output
- same on one example
- Patch
- incomplete: old names remain
- Auto-apply
- not allowed
- Seen in
- 2 models
- Worked / failed
- 8 / 0
- Last verified
- 2026-10-27
What to do
Not for automatic application — after the patch the example still uses basic_constraints, which the verified example does not: the patch covers part of the change. Show this correction to the user as a lead. Rewrite the block as shown; the failing call does not appear in the new version of the block.
Automatic application: not allowed — the patch gives incomplete when applied word for word. Automatic application is allowed only when proof.equivalent is true and proof.applicability.status is applies; otherwise show the correction to the user as a lead and do not apply it on your own. The change itself is described by kind (changed); the checks are in proof; neither follows from the other.
How to tell this applies to your code
- pyopenssl version 26.4.0 or newer is installed (checked on 26.4.0; changed between 26.0.0 and 26.4.0).
- Your code uses:
crypto.X509Extension - Or it already failed with:
AttributeError: module 'OpenSSL.crypto' has no attribute 'X509Extension'(every correction for this error)
Old and new code
basic_constraints = crypto.X509Extension(
b"basicConstraints", True, b"CA:TRUE"builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True
Error on 26.4.0:
AttributeError: module 'OpenSSL.crypto' has no attribute 'X509Extension'
Other verified fixes
The fix above passed 4 times. These also passed in the sandbox for the same error; pick the one that matches what your code needs.
Replace the line · passed 1 time · claude-sonnet-5-5 · patch: syntax error when applied word for word
basic_constraints = crypto.X509Extension(count = len(cert.extensions)Not for automatic application — applied word for word, the patch does not parse: IndentationError: unexpected indent (line 26). Show this correction to the user as a lead. Replace the old line with the new one; the rest of the code can stay.
Rewrite the block · passed 1 time · gemini-3.8-flash · patch: fails when applied word for word
ext = crypto.X509Extension(b"basicConstraints", True, b"CA:TRUE")
cert.add_extensions([ext])builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True
)Not for automatic application — the patched example does not run on 26.4.0: exit code 1, NameError: name 'builder' is not defined. Show this correction to the user as a lead. Rewrite the block as shown; the failing call does not appear in the new version of the block.
Rewrite the block · passed 1 time · claude-sonnet-5-5 · patch: fails when applied word for word
bc = crypto.X509Extension(b"basicConstraints", True, b"CA:FALSE")
cert.add_extensions([bc])builder = builder.add_extension(
x509.BasicConstraints(ca=False, path_length=None), critical=True
)Not for automatic application — the patched example does not run on 26.4.0: exit code 1, UnboundLocalError: cannot access local variable 'builder' where it is not associated with a value. Show this correction to the user as a lead. Rewrite the block as shown; the failing call does not appear in the new version of the block.
Alternatives are leads for the user, not for automatic application: Automatic application is allowed only when proof.equivalent is true and proof.applicability.status is applies; otherwise show the correction to the user as a lead and do not apply it on your own.
| Script | pyopenssl version | Result |
|---|---|---|
| Code the models wrote | 26.0.0 | works |
| Code the models wrote | 26.4.0 | fails: AttributeError |
| Verified example below | 26.4.0 | works |
| Output of the verified example | 26.4.0 | same as the original's on 26.0.0 (observed stdout of one example; not a proof of equivalent behaviour) |
| Patch applied word for word to the example | 26.4.0 | applied word for word, the patch leaves old names in use: it covers part of the change — after the patch the example still uses basic_constraints, which the verified example does not: the patch covers part of the change |
Verified example for pyopenssl 26.4.0
import datetime
import warnings
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.x509.oid import NameOID
from OpenSSL import crypto
# X509Extension is flagged as deprecated in newer pyOpenSSL releases, but it is
# still the pyOpenSSL-native way to add extensions. Suppress the warning noise.
warnings.filterwarnings("ignore", category=DeprecationWarning)
def _ext_value_str(ext):
value = ext.value
if isinstance(value, x509.BasicConstraints):
s = "CA:TRUE" if value.ca else "CA:FALSE"
if value.path_length is not None:
s += f", pathlen:{value.path_length}"
return s
return str(value)
def main():
# Generate a 2048-bit RSA key
key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 2048)
crypto_key = key.to_cryptography_key()
# Build the certificate
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "test.local")])
now = datetime.datetime.now(datetime.timezone.utc)
builder = (
x509.CertificateBuilder() # X.509 v3
.serial_number(1000)
.subject_name(subject)
.issuer_name(subject) # self-signed
.not_valid_before(now)
.not_valid_after(now + datetime.timedelta(seconds=365 * 24 * 60 * 60))
.public_key(crypto_key.public_key())
)
# Attach basicConstraints extension marking the cert as a CA
builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True
)
# Self-sign
cert = builder.sign(crypto_key, hashes.SHA256())
# Print extension info
extensions = list(cert.extensions)
count = len(extensions)
print("Extension count:", count)
for i in range(count):
ext = extensions[i]
short_name = ext.oid._name
if isinstance(short_name, bytes):
short_name = short_name.decode("ascii")
print(f"Extension {i}: {short_name} = {_ext_value_str(ext)}")
if __name__ == "__main__":
main()Source
No release-note sentence matched this change; the evidence is the sandbox check above.
Seen in: claude-sonnet-5-5, gemini-3.8-flash · First seen 2026-10-23 · Last verified 2026-10-27 · All corrections for pyopenssl
For agents
- This page as JSON:
https://formachines.ai/errata/pypi/pyopenssl/0002-openssl-crypto-x509extension/index.json - Whole database in plain text:
/errata/llms-full.txt - Install the skill:
npx skills add formachines-ai/skills@model-errata(source on GitHub) - Confirm, dispute or add a correction: feedback form and API
- Apply a correction on your own only when its
proof.auto_applyis true (Automatic application is allowed only when proof.equivalent is true and proof.applicability.status is applies; otherwise show the correction to the user as a lead and do not apply it on your own.)