golang/go · error

tls: failed to write to key log:

Error message

tls: failed to write to key log: 

What it means

If Config.KeyLogWriter is non-nil, after deriving the master secret Go calls writeKeyLog(keyLogLabelTLS12, hello.random, masterSecret) which writes '<label> <client_random> <secret>\n' to the writer. If Write returns an error, the handshake is aborted with alertInternalError and this message wrapping the underlying error.

Source

Thrown at src/crypto/tls/handshake_client.go:787

	if hs.serverHello.extendedMasterSecret {
		c.extMasterSecret = true
		hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
			hs.finishedHash.Sum())
	} else {
		if fips140tls.Required() {
			if fips140ems.Value() != "0" {
				c.sendAlert(alertHandshakeFailure)
				return errors.New("tls: FIPS 140-3 requires the use of Extended Master Secret")
			}
			fips140ems.IncNonDefault()
		}
		hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
			hs.hello.random, hs.serverHello.random)
	}
	if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
		c.sendAlert(alertInternalError)
		return errors.New("tls: failed to write to key log: " + err.Error())
	}

	if chainToSend != nil && len(chainToSend.Certificate) > 0 {
		certVerify := &certificateVerifyMsg{}

		key, ok := chainToSend.PrivateKey.(crypto.Signer)
		if !ok {
			c.sendAlert(alertInternalError)
			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
		}

		if c.vers >= VersionTLS12 {
			signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms)
			if err != nil {
				c.sendAlert(alertHandshakeFailure)
				return err
			}
			sigType, sigHash, err := typeAndHashFromSignatureScheme(signatureAlgorithm)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Point Config.KeyLogWriter at a writable path on a volume with adequate free space.
  2. If logging is best-effort, wrap the writer so Write never returns an error (log the failure out-of-band instead of failing the handshake).
  3. Set Config.KeyLogWriter to nil in production unless you actively need to debug.

Example fix

// before: a writer whose error aborts the handshake
cfg := &tls.Config{KeyLogWriter: f} // f may fail
// after: swallow write errors so the handshake never breaks
type safeWriter struct{ w io.Writer }
func (s safeWriter) Write(p []byte) (int, error) {
    n, err := s.w.Write(p)
    if err != nil { log.Printf("keylog write failed: %v", err); return len(p), nil }
    return n, nil
}
cfg := &tls.Config{KeyLogWriter: safeWriter{w: f}}
Defensive patterns

Strategy: validation

Validate before calling

// Wrap the key log writer so it never fails the handshake.
type safeKeyLogWriter struct{ w io.Writer }
func (s safeKeyLogWriter) Write(p []byte) (int, error) {
    n, err := s.w.Write(p)
    if err != nil { log.Printf("keylog write failed: %v", err); return len(p), nil }
    return n, nil
}
cfg.KeyLogWriter = safeKeyLogWriter{w: f}

Type guard

func isKeyLogWriteError(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "tls: failed to write to key log")
}

Try / catch

if _, err := tls.Dial("tcp", addr, cfg); err != nil {
    if isKeyLogWriteError(err) {
        // The key log destination is broken; drop logging and retry.
        cfg.KeyLogWriter = nil
        _, err = tls.Dial("tcp", addr, cfg)
    }
}

Prevention

When it happens

Trigger: Config.KeyLogWriter points at a file on a full disk, a deleted file, a read-only filesystem, a closed pipe, or a custom Writer whose Write returns an error.

Common situations: SSLKEYLOGFILE path on a read-only mount in containers; disk full during long packet captures; key log redirected to a pipe whose consumer exited; file permissions wrong.

Understand the failure class

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/f6ebcbe8d7741c17. Report an issue: GitHub.