{"record":{"id":"4fba5413ec0d85be","repo":"vitessio/vitess","slug":"error-v-in-writing-recovery-info-v","errorCode":null,"errorMessage":"error %v in writing recovery info %v","messagePattern":"error (.+?) in writing recovery info (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/binlog/binlogplayer/binlog_player.go","lineNumber":528,"sourceCode":"// It also tries to get the timestamp for the transaction. Two cases:\n//   - we have statements, and they start with a SET TIMESTAMP that we\n//     can parse: then we update transaction_timestamp in vreplication\n//     with it, and set ReplicationLagSeconds to now() - transaction_timestamp\n//   - otherwise (the statements are probably filtered out), we leave\n//     transaction_timestamp alone (keeping the old value), and we don't\n//     change ReplicationLagSeconds\nfunc (blp *BinlogPlayer) writeRecoveryPosition(tx *binlogdatapb.BinlogTransaction) error {\n\tposition, err := DecodePosition(tx.EventToken.Position)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnow := time.Now().Unix()\n\tupdateRecovery := GenerateUpdatePos(blp.uid, position, now, tx.EventToken.Timestamp, blp.blplStats.CopyRowCount.Get(), false)\n\n\tqr, err := blp.exec(updateRecovery)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error %v in writing recovery info %v\", err, updateRecovery)\n\t}\n\tif qr.RowsAffected != 1 {\n\t\treturn fmt.Errorf(\"cannot update vreplication table, affected %v rows\", qr.RowsAffected)\n\t}\n\n\t// Update position after successful write.\n\tblp.position = position\n\tblp.blplStats.SetLastPosition(blp.position)\n\tif tx.EventToken.Timestamp != 0 {\n\t\tblp.blplStats.ReplicationLagSeconds.Store(now - tx.EventToken.Timestamp)\n\t}\n\treturn nil\n}\n\nfunc (blp *BinlogPlayer) setVReplicationState(state binlogdatapb.VReplicationWorkflowState, message string) error {\n\tif message != \"\" {\n\t\tblp.blplStats.History.Add(&StatsHistoryRecord{\n\t\t\tTime:    time.Now(),","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/binlog/binlogplayer/binlog_player.go#L510-L546","documentation":"Thrown by writeRecoveryPosition when the UPDATE of the _vt.vreplication row (GenerateUpdatePos — storing new position, timestamp, row counts) fails to execute. The caller rolls back the current transaction so no data and no position advance is persisted, keeping replay consistent.","triggerScenarios":"blp.exec(updateRecovery) returns err: target connection lost, SQL error in the generated UPDATE (e.g. malformed position string, table _vt.vreplication missing), permissions revoked on _vt.vreplication, or target read-only.","commonSituations":"Someone dropped/altered _vt.vreplication during a migration; vttablet user lost INSERT/UPDATE grants on _vt; target in read_only during a maintenance window; connection expired between COMMIT of previous txn and this write.","solutions":["Verify _vt.vreplication exists and is intact on the target (`SELECT id, pos FROM _vt.vreplication WHERE id=<uid>`).","Check the vttablet/vreplication user's grants on _vt.vreplication (UPDATE at minimum).","Ensure target is writable (read_only=0) and reachable.","Examine the updateRecovery SQL in the error message for malformed position data; report/fix if GeneratePos output is corrupt."],"exampleFix":"// before: grants revoked\n//   GRANT SELECT, INSERT ON _vt.vreplication TO 'vt'@'%';\n// after: include UPDATE for recovery writes\n//   GRANT SELECT, INSERT, UPDATE ON _vt.vreplication TO 'vt'@'%';","handlingStrategy":"validation","validationCode":"// before streaming, verify the recovery row exists and is writable\nvar n int\nif err := targetDB.QueryRow(\n    \"SELECT COUNT(*) FROM _vt.vreplication WHERE id = ?\", uid,\n).Scan(&n); err != nil || n != 1 {\n    return fmt.Errorf(\"_vt.vreplication row id=%d missing or table unreadable\", uid)\n}\n// also verify UPDATE grant:\n// SHOW GRANTS FOR CURRENT_USER() — must include UPDATE ON _vt.*","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never drop/alter _vt.vreplication while streams are running","Keep vttablet user grants on _vt.vreplication (SELECT, INSERT, UPDATE)","Avoid read_only maintenance windows while vreplication is active","Alert on 'error in writing recovery info' — it means replay progress is not being persisted"],"tags":["mysql","vreplication","recovery-position","sql-error"],"backgroundTag":"vreplication-update-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}