golang/go · error
tls: invalid reconstructed inner client hello
Error message
tls: invalid reconstructed inner client hello
What it means
Thrown after ECH inner ClientHello reconstruction when the fully reassembled bytes (decrypted inner fields plus expanded outer extensions substituted in) fail to parse as a valid ClientHello via clientHelloMsg.unmarshal(). This is a comprehensive final validation that catches inconsistencies not detected by earlier field-level checks, such as duplicate extensions, invalid field values, or structural contradictions introduced during extension expansion.
Source
Thrown at src/crypto/tls/ech.go:370
})
}
} else {
recon.AddUint16(extension)
recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
recon.AddBytes(extData)
})
}
}
})
})
reconBytes, err := recon.Bytes()
if err != nil {
return nil, err
}
inner := &clientHelloMsg{}
if !inner.unmarshal(reconBytes) {
return nil, errors.New("tls: invalid reconstructed inner client hello")
}
if !bytes.Equal(inner.encryptedClientHello, []byte{uint8(innerECHExt)}) {
return nil, errInvalidECHExt
}
hasTLS13 := false
for _, v := range inner.supportedVersions {
// Skip GREASE values (values of the form 0x?A0A).
// GREASE (Generate Random Extensions And Sustain Extensibility) is a mechanism used by
// browsers like Chrome to ensure TLS implementations correctly ignore unknown values.
// GREASE values follow a specific pattern: 0x?A0A, where ? can be any hex digit.
// These values should be ignored when processing supported TLS versions.
if v&0x0F0F == 0x0A0A && v&0xff == v>>8 {
continue
}
// Ensure at least TLS 1.3 is offered.View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure the ECH client does not duplicate extensions between the inner-only set and the outer_extensions compressed reference
- Verify that all extension data in the outer hello is consistent with the inner hello's fields (e.g., supported_versions, key_share, etc.)
- Check for extension type collisions between inner and outer extension sets
- Test the client against a reference server implementation to identify reconstruction failures
Defensive patterns
Strategy: validation
Try / catch
// Wrapped into errInvalidECHExt by processECHClientHello.
Prevention
- Ensure no duplicate extensions exist between the inner-only set and the outer_extensions compressed references
- Verify inner and outer hello extension data is mutually consistent
- Test the full reconstruction path with reference ECH clients
When it happens
Trigger: The reconstructed inner ClientHello — assembled from decrypted inner content with outer_extensions expanded to their full extension data from the outer hello — contains data that fails the complete ClientHello parser. Possible causes: duplicate extension types after expansion, invalid cipher suite values, unsupported version fields, or extension data that is individually valid but collectively contradictory.
Common situations: The expansion of outer extensions introduced a duplicate extension that also exists in the inner-only set. The outer hello's extension data is incompatible with the inner hello's structure. A client bug where the inner and outer hello share an extension with conflicting values. Decryption corruption that produces fields valid individually but invalid collectively.
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 outer extensions
- tls: client sent invalid encrypted client hello extension
- tls: client sent encrypted_client_hello extension with unsup
- tls: client sent encrypted_client_hello extension but did no
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/0c974b7d3aff819d.
Report an issue: GitHub.