{"record":{"id":"5b7633504c2a102c","repo":"Tencent/WeKnora","slug":"sandbox-binding-version-must-be-d-got-d","errorCode":null,"errorMessage":"sandbox binding version must be %d, got %d","messagePattern":"sandbox binding version must be (.+?), got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sandbox/session_binding.go","lineNumber":70,"sourceCode":"\t//\n\t// Bindings written before this field existed carry an empty value. They are\n\t// deliberately still valid — refusing them would break every live session\n\t// on upgrade — and simply match no config until they are rebuilt.\n\tConfigID string `json:\"config_id,omitempty\"`\n\n\t// StaleAt marks a binding whose sandbox boots an image the config has\n\t// since replaced. The sandbox keeps serving until the session's next\n\t// resolve, which destroys and recreates it; see InvalidateByConfig.\n\tStaleAt *time.Time `json:\"stale_at,omitempty\"`\n}\n\n// Validate checks a binding against the current schema and authoritative key.\nfunc (b SessionSandboxBinding) Validate(key SessionSandboxKey) error {\n\tif err := key.Validate(); err != nil {\n\t\treturn err\n\t}\n\tif b.Version != SessionSandboxBindingVersion {\n\t\treturn fmt.Errorf(\n\t\t\t\"sandbox binding version must be %d, got %d\",\n\t\t\tSessionSandboxBindingVersion,\n\t\t\tb.Version,\n\t\t)\n\t}\n\tif !isRemoteProvider(b.Provider) {\n\t\treturn fmt.Errorf(\"unsupported sandbox binding provider %q\", b.Provider)\n\t}\n\tif b.TenantID != key.TenantID || b.SessionID != key.SessionID {\n\t\treturn errors.New(\"sandbox binding identity does not match its key\")\n\t}\n\tif strings.TrimSpace(b.SandboxID) == \"\" {\n\t\treturn errors.New(\"sandbox binding requires sandbox ID\")\n\t}\n\tif strings.TrimSpace(b.TemplateID) == \"\" {\n\t\treturn errors.New(\"sandbox binding requires template ID\")\n\t}\n\tif b.CreatedAt.IsZero() {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/sandbox/session_binding.go#L52-L88","documentation":"SessionSandboxBinding.Validate enforces that a persisted binding was written with the current SessionSandboxBindingVersion schema. If b.Version differs (older rows from a previous release, or corrupted data) it returns this formatted mismatch error naming the expected and actual versions. Callers like BeginTurn/EndTurn/Get depend on it to reject stale bindings early.","triggerScenarios":"Loading a binding from storage (via Get or during BeginTurn/EndTurn) that was written by an older library version with a different binding schema version, or a binding struct populated by hand with a wrong Version field.","commonSituations":"Rolling deploy where old-version bindings persist in Redis while the new binary validates them; hand-crafted test fixtures with Version left at zero value; data migrations not run.","solutions":["Run the library's binding data migration or rewrite stored bindings to the current SessionSandboxBindingVersion","Delete/invalidate stale bindings so they are recreated on the next BeginTurn","Ensure all service instances run the same library version during rollouts","Set Version: SessionSandboxBindingVersion explicitly when constructing bindings in tests"],"exampleFix":"// before\nb := sandbox.SessionSandboxBinding{Provider: \"docker\", SandboxID: \"sbx1\"}\n// after\nb := sandbox.SessionSandboxBinding{\n    Provider: \"docker\", SandboxID: \"sbx1\",\n    Version: sandbox.SessionSandboxBindingVersion,\n}","handlingStrategy":"type-guard","validationCode":"if b.Version != sandbox.SessionSandboxBindingVersion {\n    return migrateOrRecreateBinding(b)\n}","typeGuard":"func bindingCurrent(b sandbox.SessionSandboxBinding) bool {\n    return b.Version == sandbox.SessionSandboxBindingVersion\n}","tryCatchPattern":"if err := b.Validate(key); err != nil {\n    var verr *fmt.Errorf\n    if errors.As(err, &verr) && strings.Contains(err.Error(), \"version must be\") {\n        return recreateBinding(ctx, key) // drop stale-schema binding\n    }\n    return err\n}","preventionTips":["Always set Version from the exported constant, never a literal","Run data migrations before deploying schema-version bumps","Keep library versions consistent across all instances"],"tags":["go","schema","versioning","binding-validation"],"backgroundTag":"schema-version-mismatch","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}