{"record":{"id":"058ae08f61518554","repo":"temporalio/temporal","slug":"w-provided-table-version-v-current-table-versi","errorCode":null,"errorMessage":"%w. provided table version: %v current table version: %v","messagePattern":"%w\\. provided table version: (.+?) current table version: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"common/persistence/cassandra/nexus_endpoint_store.go","lineNumber":141,"sourceCode":"\t\trowType, err := getTypedFieldFromRow[int](\"type\", row1)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"CreateOrUpdateNexusEndpoint: error reading type from CAS result row: %w\", err)\n\t\t}\n\t\tswitch rowType {\n\t\tcase rowTypePartitionStatus:\n\t\t\tpreviousPartitionStatus, previousEndpoint = row1, row2\n\t\tcase rowTypeNexusEndpoint:\n\t\t\tpreviousPartitionStatus, previousEndpoint = row2, row1\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"CreateOrUpdateNexusEndpoint: unexpected row type %d in CAS result\", rowType)\n\t\t}\n\n\t\tcurrentTableVersion, err := getTypedFieldFromRow[int64](\"version\", previousPartitionStatus)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error retrieving current table version: %w\", err)\n\t\t}\n\t\tif currentTableVersion != request.LastKnownTableVersion {\n\t\t\treturn fmt.Errorf(\"%w. provided table version: %v current table version: %v\",\n\t\t\t\tp.ErrNexusTableVersionConflict,\n\t\t\t\trequest.LastKnownTableVersion,\n\t\t\t\tcurrentTableVersion)\n\t\t}\n\n\t\tcurrentVersion, err := getTypedFieldFromRow[int64](\"version\", previousEndpoint)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error retrieving current endpoint version: %w\", err)\n\t\t}\n\t\tif currentVersion != request.Endpoint.Version {\n\t\t\treturn fmt.Errorf(\"%w. provided endpoint version: %v current endpoint version: %v\",\n\t\t\t\tp.ErrNexusEndpointVersionConflict,\n\t\t\t\trequest.Endpoint.Version,\n\t\t\t\tcurrentVersion)\n\t\t}\n\n\t\t// This should never happen. This means the request had the correct versions and gocql did not\n\t\t// return an error but for some reason the update was not applied.","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/cassandra/nexus_endpoint_store.go#L123-L159","documentation":"CreateOrUpdateNexusEndpoint performs an optimistic-concurrency update on the nexus endpoints table: the request carries LastKnownTableVersion, which must equal the current table version row read from Cassandra. When they differ, someone else modified the endpoint table between the caller's read and write, and the persistence layer rejects the write with ErrNexusTableVersionConflict wrapped with both versions.","triggerScenarios":"Two concurrent admin/frontend calls to CreateOrUpdateNexusEndpoint (or an update racing a create/delete) using a stale LastKnownTableVersion; also exercised by concurrent-update tests like testCassandraNexusEndpointStoreConcurrentUpdate.","commonSituations":"Multiple operators updating Nexus endpoints (callbacks, workers) simultaneously via tctl/UI; a frontend instance holding a cached table version while another instance already bumped it; retries of an old request after a competing write succeeded.","solutions":["Re-read the current endpoint/table state and retry the update with the fresh LastKnownTableVersion.","Treat this as an expected conflict: wrap the call in a retry-with-backoff loop that refetches the version on ErrNexusTableVersionConflict.","Serialize admin endpoint mutations through a single path (e.g. frontend leader) to reduce contention.","Check for client code caching table versions across multiple update calls and refresh it each time."],"exampleFix":"// before\n_, err := store.CreateOrUpdateNexusEndpoint(ctx, reqWithStaleVersion)\nreturn err // fails on concurrent modification\n// after\nfor attempt := 0; attempt < maxAttempts; attempt++ {\n    latest, err := store.GetNexusEndpoints(ctx, pageToken)\n    if err != nil {\n        return err\n    }\n    req.LastKnownTableVersion = latest.TableVersion\n    _, err = store.CreateOrUpdateNexusEndpoint(ctx, req)\n    if !errors.Is(err, p.ErrNexusTableVersionConflict) {\n        return err\n    }\n}","handlingStrategy":"retry","validationCode":"current, err := store.GetNexusEndpoints(ctx, token) // refetch before write\nif err != nil {\n    return err\n}\nif current.TableVersion != req.LastKnownTableVersion {\n    req.LastKnownTableVersion = current.TableVersion // refresh instead of failing\n}","typeGuard":"func isTableVersionConflict(err error) bool {\n    return errors.Is(err, p.ErrNexusTableVersionConflict)\n}","tryCatchPattern":"_, err := store.CreateOrUpdateNexusEndpoint(ctx, req)\nif errors.Is(err, p.ErrNexusTableVersionConflict) {\n    // concurrent modification: refetch table version and retry with backoff\n    return retryWithFreshVersion(ctx, req)\n}\nreturn err","preventionTips":["Always fetch the current table version immediately before an update; never cache it across calls","Implement bounded retry-with-backoff on ErrNexusTableVersionConflict in admin tooling","Route endpoint mutations through a single coordination point to reduce write contention","Monitor conflict rates; sustained conflicts indicate a stale-version client bug"],"tags":["cassandra","persistence","optimistic-concurrency","nexus-endpoint"],"backgroundTag":"version-conflict","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}