{"record":{"id":"67380cb9756839ed","repo":"gastownhall/beads","slug":"identity-write-request-w","errorCode":null,"errorMessage":"identity: write request: %w","messagePattern":"identity: write request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/identity/control.go","lineNumber":58,"sourceCode":"// Identify authenticates to a proxy control listener and returns its identity.\nfunc Identify(host string, controlPort int, secret string, timeout time.Duration) (*IdentReply, error) {\n\taddr := net.JoinHostPort(host, strconv.Itoa(controlPort))\n\tconn, err := net.DialTimeout(\"tcp\", addr, timeout)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"identity: dial control listener: %w\", err)\n\t}\n\tdefer func() { _ = conn.Close() }()\n\n\tif err := conn.SetDeadline(time.Now().Add(timeout)); err != nil {\n\t\treturn nil, fmt.Errorf(\"identity: set control deadline: %w\", err)\n\t}\n\tnonceBytes := make([]byte, identNonceBytes)\n\tif _, err := rand.Read(nonceBytes); err != nil {\n\t\treturn nil, fmt.Errorf(\"identity: generate request nonce: %w\", err)\n\t}\n\tnonce := hex.EncodeToString(nonceBytes)\n\tif _, err := io.WriteString(conn, \"IDENT \"+secret+\" \"+nonce+\"\\n\"); err != nil {\n\t\treturn nil, fmt.Errorf(\"identity: write request: %w\", err)\n\t}\n\n\tline, err := bufio.NewReader(io.LimitReader(conn, maxIdentReplyBytes+1)).ReadString('\\n')\n\tif errors.Is(err, io.EOF) && len(line) == 0 {\n\t\treturn nil, ErrIdentRefused\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"identity: read reply: %w\", err)\n\t}\n\tif len(line) > maxIdentReplyBytes {\n\t\treturn nil, errors.New(\"identity: oversized reply\")\n\t}\n\n\tvar reply IdentReply\n\tif err := json.Unmarshal([]byte(line), &reply); err != nil {\n\t\treturn nil, fmt.Errorf(\"identity: decode reply: %w\", err)\n\t}\n\tif err := VerifyIdentReply(reply, secret, nonce); err != nil {","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/identity/control.go#L40-L76","documentation":"Identify writes the IDENT request line (secret + nonce) to the control connection. This error wraps the io.WriteString failure, meaning the TCP write failed after dialing — the connection broke mid-handshake.","triggerScenarios":"The control listener closed or reset the connection before/while the request was written; network drop between dial and write; write deadline already exceeded.","commonSituations":"Listener crashed or refused the connection immediately after accept; wrong service on the port that closes on unknown input; very tight timeout expiring between dial and write; intermediary firewall sending RST.","solutions":["Confirm the port is actually the proxy's control listener speaking the IDENT protocol","Increase the timeout so the write is not cut off","Check proxy logs for a crash or early connection close","Retry; if the listener is flapping, restart the proxy"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"reply, err := Identify(host, port, secret, timeout)\nif err != nil && strings.Contains(err.Error(), \"write request\") {\n\t// connection dropped mid-handshake; retry with backoff, check proxy health\n}","preventionTips":["Point Identify at the real control listener, not another service","Use a timeout generous enough to cover dial+write+read","Watch proxy logs for crashes that close connections early"],"tags":["network","tcp","write","dbproxy","handshake"],"backgroundTag":"connection-reset-by-peer","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}