{"record":{"id":"704d0f3ed40b30ea","repo":"Tencent/WeKnora","slug":"sandbox-config-is-being-modified-by-another-reques","errorCode":null,"errorMessage":"sandbox config is being modified by another request","messagePattern":"sandbox config is being modified by another request","errorType":"error_code","errorClass":null,"httpStatus":409,"severity":"error","filePath":"internal/application/repository/tenant_sandbox_config.go","lineNumber":120,"sourceCode":"\t\t\t\"name\":         e.Name,\n\t\t\t\"description\":  e.Description,\n\t\t\t\"sandbox_type\": e.SandboxType,\n\t\t\t\"config\":       e.Config,\n\t\t\t\"updated_at\":   time.Now(),\n\t\t}).Error\n}\n\nfunc (r *tenantSandboxConfigRepository) SoftDelete(\n\tctx context.Context, tenantID uint64, id string,\n) error {\n\treturn r.db.WithContext(ctx).\n\t\tWhere(\"tenant_id = ? AND id = ?\", tenantID, id).\n\t\tDelete(&types.TenantSandboxConfigEntity{}).Error\n}\n\n// ErrSandboxConfigCordoned is returned by SetCordon when another request\n// already holds a fresh cordon lease on the same config row.\nvar ErrSandboxConfigCordoned = errors.New(\"sandbox config is being modified by another request\")\n\n// SetCordon must be committed before the caller lists provider sandboxes:\n// resolution paths only stop creating sandboxes once they can see it.\n//\n// The update is a conditional CAS: it refuses to overwrite a cordon that is\n// still within the lease window, so two concurrent identity-change requests\n// cannot race past each other.\nfunc (r *tenantSandboxConfigRepository) SetCordon(\n\tctx context.Context, tenantID uint64, id string, at time.Time,\n) error {\n\tresult := r.db.WithContext(ctx).\n\t\tModel(&types.TenantSandboxConfigEntity{}).\n\t\tWhere(\"tenant_id = ? AND id = ?\", tenantID, id).\n\t\tWhere(\"cordoned_at IS NULL OR cordoned_at < ?\", at.Add(-types.SandboxCordonLease)).\n\t\tUpdate(\"cordoned_at\", at)\n\tif result.Error != nil {\n\t\treturn result.Error\n\t}","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/repository/tenant_sandbox_config.go#L102-L138","documentation":"Sentinel ErrSandboxConfigCordoned returned by SetCordon when a compare-and-set style UPDATE affects 0 rows — meaning another request already holds a fresh cordon lease on the same sandbox config row. A concurrency-control signal, not a data error; the handler responds with a cordon-conflict response.","triggerScenarios":"Thrown at internal/application/repository/tenant_sandbox_config.go:120 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Treat the config as already cordoned; poll or read the current cordon state instead of re-issuing","Retry cordon after the existing lease expires if a fresh cordon is genuinely needed"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}