iflytek/astron-agent · critical

ensure tenant bootstrap app failed

Error message

ensure tenant bootstrap app failed: %w

What it means

ensureAndLockTenantBootstrapApp inserts (or confirms) the reserved 'admin' bootstrap app row in tb_app; any SQL failure during that insert is wrapped as 'ensure tenant bootstrap app failed'. This runs inside the bootstrap transaction before credentials are rotated.

Solutions

  1. Read the wrapped cause: if duplicate-key, inspect the existing tb_app row for the reserved app_id and reconcile it manually or adopt it.
  2. Run database migrations/tools to ensure the schema matches what the bootstrap code expects.
  3. Grant the bootstrap MySQL user INSERT/SELECT/UPDATE/LOCK TABLES privileges on tb_app and tb_auth.
  4. Check MySQL connectivity and error log for transient failures, then re-run bootstrap (it is idempotent within its transaction).

Example fix

// before: failing due to unexpected pre-existing row
INSERT INTO tb_app (app_id, ...) VALUES ('reserved-tenant', ...)
-- after: pre-reconcile conflicting legacy row first
-- DELETE or UPDATE the legacy row for the reserved app_id, then re-run bootstrap
UPDATE tb_app SET is_delete = 1 WHERE app_id = 'reserved-tenant' AND source <> 'bootstrap';
Defensive patterns

Strategy: retry

Validate before calling

var n int
if err := db.QueryRow(`SELECT COUNT(*) FROM tb_app WHERE app_id = ?`, reservedID).Scan(&n); err != nil || n > 1 {
    return fmt.Errorf("conflicting rows for reserved app %s", reservedID)
}

Try / catch

if err := ensureAndLockTenantBootstrapApp(ctx, tx, creds, now); err != nil {
    if isDuplicateKey(err) {
        return adoptExistingBootstrapApp(ctx, tx, creds) // reconcile legacy row
    }
    return fmt.Errorf("ensure tenant bootstrap app failed: %w", err)
}

Prevention

When it happens

Trigger: The INSERT of the reserved tenant app fails — duplicate app_id from a conflicting row, schema mismatch, permission denied for the MySQL user, or connection loss.

Common situations: Manual/legacy data in tb_app already uses the reserved tenant ID with different columns; migration out of sync so tb_app lacks expected columns; bootstrap DB user lacks INSERT privilege; MySQL connection dropped mid-transaction.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/66e748cc6647c8b0. Report an issue: GitHub.

Appendix: source

Thrown at core/tenant/tools/database/bootstrap_credentials.go:134

) error {
	if _, err := transaction.ExecContext(
		ctx,
		`INSERT IGNORE INTO tb_app
  (update_time, registration_time, app_id, app_name, dev_id, channel_id, source, is_disable, app_desc, is_delete, extend)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
		now,
		now,
		credentials.TenantID,
		"星辰租户",
		1,
		"0",
		"admin",
		false,
		"星辰租户",
		false,
		"",
	); err != nil {
		return fmt.Errorf("ensure tenant bootstrap app failed: %w", err)
	}

	// Serialize reconciliation across replicas on the reserved app row before
	// taking any auth-index gap locks or rotating managed credentials.
	var lockedAppID string
	var lockedAppDisabled sql.NullBool
	var lockedAppDeleted sql.NullBool
	if err := transaction.QueryRowContext(
		ctx,
		`SELECT app_id, is_disable, is_delete FROM tb_app WHERE app_id = ? FOR UPDATE`,
		credentials.TenantID,
	).Scan(&lockedAppID, &lockedAppDisabled, &lockedAppDeleted); err != nil {
		return fmt.Errorf("lock tenant bootstrap app failed: %w", err)
	}
	if lockedAppID != credentials.TenantID {
		return errors.New("locked tenant bootstrap app does not match the reserved tenant ID")
	}
	if !lockedAppDisabled.Valid || lockedAppDisabled.Bool ||

View on GitHub (pinned to 5e758547a8)