{"record":{"id":"7325e7a5202c6fda","repo":"vitessio/vitess","slug":"mismatched-shardsession-count-originally-d-now","errorCode":null,"errorMessage":"mismatched ShardSession count: originally %d, now %d","messagePattern":"mismatched ShardSession count: originally (.+?), now (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vitessdriver/driver.go","lineNumber":360,"sourceCode":"\t}\n\n\t// this is designed to be run after all new work has been done in the tx, similar to\n\t// where you would traditionally run a tx.Commit, to help prevent you from silently\n\t// losing transactional data.\n\tvalidationFunc := func() error {\n\t\tvar sessionToken string\n\t\tsessionToken, err = SessionTokenFromTx(ctx, tx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsession, err = sessionTokenToSession(sessionToken)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif len(session.ShardSessions) > originalShardSessionCount {\n\t\t\treturn fmt.Errorf(\"mismatched ShardSession count: originally %d, now %d\",\n\t\t\t\toriginalShardSessionCount, len(session.ShardSessions),\n\t\t\t)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\treturn tx, validationFunc, nil\n}\n\n// SessionTokenFromTx serializes the sessionFromToken on the tx, which can be reconstituted\n// into a *sql.Tx using DistributedTxFromSessionToken\nfunc SessionTokenFromTx(ctx context.Context, tx *sql.Tx) (string, error) {\n\tvar sessionToken string\n\n\terr := tx.QueryRowContext(ctx, \"vt_session_token\").Scan(&sessionToken)\n\tif err != nil {\n\t\treturn \"\", err","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vitessdriver/driver.go#L342-L378","documentation":"The vitess database/sql driver stores shard sessions returned in session tokens. When a session token passed in contains MORE ShardSessions than the original count recorded when the session was first created, something replaced or regenerated the session token mid-transaction; the driver refuses to commit state that grew beyond what it created, returning this mismatch error.","triggerScenarios":"Calling Commit (via the driver's commit path in vitessdriver) with a session token whose ShardSessions slice length exceeds originalShardSessionCount — typically when a session token from a different transaction/lifetime is committed, or tokens are reused/shared across transactions incorrectly.","commonSituations":"Application code reusing a session token across transactions or copying it between connections; serialization/deserialization round-trips that merged session states; driver misuse where Begin/Commit is interleaved with tokens from another session.","solutions":["Ensure each transaction's session token is used only within that transaction — never reuse or share tokens across transactions or connections.","Get a fresh session token by beginning a new transaction instead of re-committing an old token.","If using the driver directly, verify the token passed to Commit originates from the same conn/session that called Begin."],"exampleFix":"// before: token reused across transactions\ntoken := tx1.SessionToken()\ntx2.CommitWithToken(token) // mismatch\n// after: commit the token of the same transaction\ntoken := tx1.SessionToken()\ntx1.CommitWithToken(token)","handlingStrategy":"validation","validationCode":"token := tx.SessionToken()\nsess, err := sessionTokenToSession(token)\nif err != nil {\n    return err\n}\nif len(sess.ShardSessions) != expectedSessionCount {\n    return fmt.Errorf(\"token for wrong transaction: %d sessions\", len(sess.ShardSessions))\n}","typeGuard":"func isShardSessionCountMismatch(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"mismatched ShardSession count\")\n}","tryCatchPattern":"if err := conn.CommitWithToken(token); err != nil {\n    if isShardSessionCountMismatch(err) {\n        return fmt.Errorf(\"session token reused across transactions; start a new transaction: %w\", err)\n    }\n    return err\n}","preventionTips":["Never share or reuse session tokens across transactions or connections","Commit only with the token obtained from the same transaction you began","Avoid copying/stashing tokens in app state that can outlive the transaction"],"tags":["go-driver","database-sql","transactions","shard-sessions"],"backgroundTag":"session-token-mismatch","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}