{"record":{"id":"1f8dc09af21d7e5d","repo":"iflytek/astron-agent","slug":"reserved-tenant-bootstrap-app-is-disabled-or-deleted","errorCode":null,"errorMessage":"reserved tenant bootstrap app is disabled or deleted","messagePattern":"reserved tenant bootstrap app is disabled or deleted","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tenant/tools/database/bootstrap_credentials.go","lineNumber":154,"sourceCode":"\n\t// Serialize reconciliation across replicas on the reserved app row before\n\t// taking any auth-index gap locks or rotating managed credentials.\n\tvar lockedAppID string\n\tvar lockedAppDisabled sql.NullBool\n\tvar lockedAppDeleted sql.NullBool\n\tif err := transaction.QueryRowContext(\n\t\tctx,\n\t\t`SELECT app_id, is_disable, is_delete FROM tb_app WHERE app_id = ? FOR UPDATE`,\n\t\tcredentials.TenantID,\n\t).Scan(&lockedAppID, &lockedAppDisabled, &lockedAppDeleted); err != nil {\n\t\treturn fmt.Errorf(\"lock tenant bootstrap app failed: %w\", err)\n\t}\n\tif lockedAppID != credentials.TenantID {\n\t\treturn errors.New(\"locked tenant bootstrap app does not match the reserved tenant ID\")\n\t}\n\tif !lockedAppDisabled.Valid || lockedAppDisabled.Bool ||\n\t\t!lockedAppDeleted.Valid || lockedAppDeleted.Bool {\n\t\treturn errors.New(\"reserved tenant bootstrap app is disabled or deleted\")\n\t}\n\treturn nil\n}\n\nfunc findTenantBootstrapCredential(\n\tctx context.Context,\n\ttransaction bootstrapTransaction,\n\tcredentials config.TenantBootstrapCredentials,\n) (bool, error) {\n\tvar collisionOwner string\n\terr := transaction.QueryRowContext(\n\t\tctx,\n\t\t`SELECT app_id\nFROM tb_auth\nWHERE api_key = ? AND app_id <> ? AND is_delete = 0\nLIMIT 1 FOR UPDATE`,\n\t\tcredentials.APIKey,\n\t\tcredentials.TenantID,","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/tenant/tools/database/bootstrap_credentials.go#L136-L172","documentation":"After locking the bootstrap app row, this check fails if is_disable or is_delete is NULL (invalid) or true — i.e., the reserved tenant bootstrap app has been disabled or soft-deleted, so reconciliation cannot safely use it.","triggerScenarios":"tb_app row for the reserved tenant has is_disable=1, is_delete=1, or NULL values for either column when reconcileTenantBootstrapTransaction executes.","commonSituations":"Someone disabled or soft-deleted the bootstrap app via admin tooling; a migration left the flag columns NULL; soft-delete cleanup job removed the reserved app.","solutions":["Re-enable the app: UPDATE tb_app SET is_disable=0, is_delete=0 WHERE app_id = <reserved tenant ID>","Backfill NULL flag columns to 0 for the bootstrap app","Investigate which admin operation/job disabled or deleted the reserved app and exclude reserved apps from it","Re-run bootstrap reconciliation after restoring the row state"],"exampleFix":"// before\nUPDATE tb_app SET is_disable = 1 WHERE app_id = 'reserved-tenant';\n// after\nUPDATE tb_app SET is_disable = 0, is_delete = 0 WHERE app_id = 'reserved-tenant';","handlingStrategy":"validation","validationCode":"// preflight outside the transaction\nvar disabled, deleted sql.NullBool\n_ = db.QueryRow(`SELECT is_disable, is_delete FROM tb_app WHERE app_id = ?`, tenantID).Scan(&disabled, &deleted)\nif (disabled.Valid && disabled.Bool) || (deleted.Valid && deleted.Bool) { /* restore row before bootstrap */ }","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"disabled or deleted\") { restoreReservedAppRow(db, tenantID); return reconcileBootstrap(ctx, creds) }","preventionTips":["Exclude reserved bootstrap apps from admin disable/delete tooling","Backfill is_disable/is_delete to NOT NULL DEFAULT 0","Alert on state changes to reserved tenant rows"],"tags":["go","mysql","bootstrap","soft-delete"],"backgroundTag":"invalid-state-transition","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}