{"record":{"id":"22bf4f4b3aca8a6f","repo":"iflytek/astron-agent","slug":"adopt-tenant-bootstrap-credential-failed-w","errorCode":null,"errorMessage":"adopt tenant bootstrap credential failed: %w","messagePattern":"adopt tenant bootstrap credential failed: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tenant/tools/database/bootstrap_credentials.go","lineNumber":229,"sourceCode":") error {\n\t// A strong pair explicitly configured by the deployment may already have\n\t// been created through Tenant's public API on an older release. Because it\n\t// belongs to the reserved app and exactly matches the current deployment\n\t// Secret, adopt it into managed ownership so a later rotation can retire it.\n\tif _, err := transaction.ExecContext(\n\t\tctx,\n\t\t`UPDATE tb_auth\nSET extend = ?, update_time = ?\nWHERE app_id = ? AND api_key = ? AND api_secret = ? AND is_delete = 0\n  AND COALESCE(extend, '') <> ?`,\n\t\ttenantBootstrapManagedMarker,\n\t\tnow,\n\t\tcredentials.TenantID,\n\t\tcredentials.APIKey,\n\t\tcredentials.Secret,\n\t\ttenantBootstrapManagedMarker,\n\t); err != nil {\n\t\treturn fmt.Errorf(\"adopt tenant bootstrap credential failed: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc rotateTenantBootstrapCredentials(\n\tctx context.Context,\n\ttransaction bootstrapTransaction,\n\tcredentials config.TenantBootstrapCredentials,\n\tnow string,\n) error {\n\tif _, err := transaction.ExecContext(\n\t\tctx,\n\t\t`UPDATE tb_auth\nSET is_delete = 1, update_time = ?\nWHERE api_key = ? AND api_secret = ?`,\n\t\tnow,\n\t\tconfig.LegacyTenantKey,\n\t\tconfig.LegacyTenantSecret,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/tenant/tools/database/bootstrap_credentials.go#L211-L247","documentation":"adoptTenantBootstrapCredential wraps a failure of the UPDATE that marks an existing (older-release, manually created via the public API) tb_auth credential row as tenant-managed by setting extend=tenantBootstrapManagedMarker. Any MySQL/driver error from ExecContext is wrapped with %w. The reconciliation is aborted so the credential is not silently left half-adopted.","triggerScenarios":"transaction.ExecContext(\"UPDATE tb_auth SET extend=?, update_time=? WHERE app_id=? AND api_key=? AND api_secret=? AND is_delete=0 AND COALESCE(extend,'')<>?\" ) returns a non-nil error during reconcileTenantBootstrapTransaction — e.g. deadlocked with another writer, lock wait timeout, connection reset, or read-only replica.","commonSituations":"Concurrent tenant bootstrap runs deadlock on the same tb_auth rows; the DB connection pool is exhausted; the statement is routed to a read-only replica; the table is corrupted or under schema migration (ALTER TABLE metadata lock).","solutions":["Inspect the wrapped driver error in tenant service logs (deadlock vs timeout vs connection loss).","For deadlock/lock-wait-timeout, simply retry: the whole reconcile runs in a transaction and is idempotent.","Ensure the reconcile transaction is executed against the primary, not a read-only replica.","Check MySQL error log for InnoDB deadlock details and serialize concurrent bootstrap runs (e.g. advisory lock).","Verify connection-pool sizing (max_open_conns) is adequate for the number of concurrent reconcilers."],"exampleFix":"// before\nif err := reconcileTenantBootstrapTransaction(ctx, tx, creds); err != nil {\n    return err\n}\n\n// after: retry transient DB failures\nfor i := 0; i < 3; i++ {\n    err := reconcileTenantBootstrapTransaction(ctx, tx, creds)\n    if err == nil || !isRetryableDBError(err) {\n        return err\n    }\n    time.Sleep(time.Duration(1<<i) * 100 * time.Millisecond)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := reconcile(ctx, tx, creds); err != nil {\n    if isDeadlockOrTimeout(err) {\n        return retryWithBackoff(ctx, func() error { return reconcile(ctx, tx, creds) })\n    }\n    return err\n}","preventionTips":["Keep reconcile transactions short to reduce lock contention.","Run only one reconciler per deployment (leader election).","Point writes at the primary, never a read replica.","Retry idempotent transactional operations on transient DB errors."],"tags":["database","mysql","tenant-bootstrap","go"],"backgroundTag":"database-write-failed","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}