golang/go · error
tls: invalid outer extensions
Error message
tls: invalid outer extensions
What it means
Thrown during ECH inner ClientHello reconstruction when the outer_extensions compressed reference list includes the encrypted_client_hello extension type. RFC 9460 explicitly forbids this because the inner ClientHello carries its own ECH indicator (a single byte set to innerECHExt=1), and referencing the outer ECH extension would create ambiguity and potential security issues.
Source
Thrown at src/crypto/tls/ech.go:337
if !extensions.ReadUint16(&extension) ||
!extensions.ReadUint16LengthPrefixed(&extData) {
recon.SetError(errors.New("tls: invalid inner client hello"))
return
}
if extension == extensionECHOuterExtensions {
if !extData.ReadUint8LengthPrefixed(&extData) {
recon.SetError(errors.New("tls: invalid inner client hello"))
return
}
var i int
for !extData.Empty() {
var extType uint16
if !extData.ReadUint16(&extType) {
recon.SetError(errors.New("tls: invalid inner client hello"))
return
}
if extType == extensionEncryptedClientHello {
recon.SetError(errors.New("tls: invalid outer extensions"))
return
}
for ; i <= len(rawOuterExts); i++ {
if i == len(rawOuterExts) {
recon.SetError(errors.New("tls: invalid outer extensions"))
return
}
if rawOuterExts[i].extType == extType {
break
}
}
recon.AddUint16(rawOuterExts[i].extType)
recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
recon.AddBytes(rawOuterExts[i].data)
})
}
} else {
recon.AddUint16(extension)View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure the ECH client implementation excludes encrypted_client_hello from the outer_extensions compressed list — this is explicitly forbidden by RFC 9460
- Update the client ECH library to the latest version that handles the inner/outer extension separation correctly
- If using a custom ECH implementation, verify that the extension compression logic filters out the ECH extension type
- Report as a bug to the client library vendor if using a third-party ECH implementation
Defensive patterns
Strategy: validation
Try / catch
// Wrapped into errInvalidECHExt by processECHClientHello.
Prevention
- Ensure ECH client excludes encrypted_client_hello from the outer_extensions list (RFC 9460 requirement)
- Update client ECH libraries to RFC 9460-compliant versions
- Audit custom ECH implementations for this specific protocol violation
When it happens
Trigger: The inner ClientHello's outer_extensions list contains the extensionEncryptedClientHello type ID, which is prohibited by the ECH specification.
Common situations: A non-compliant ECH client implementation that incorrectly includes the ECH extension in the compressed outer extensions reference. A deliberate protocol violation attempt. A client using an incompatible ECH draft version with different rules.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: malformed encrypted_client_hello extension
- tls: invalid reconstructed inner client hello
- tls: client sent encrypted_client_hello extension with unsup
- tls: client sent encrypted_client_hello extension but did no
- tls: downgrade attempt detected, possibly due to a MitM atta
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/5f6f2e086c273551.
Report an issue: GitHub.