plandex-ai/plandex · error

error deleting custom providers: %v

Error message

error deleting custom providers: %v

What it means

DeleteCustomProviders wraps any failure of the batched DELETE on custom_providers (scoped by org_id and id ANY($2)) with this message. Zero rows deleted is not an error; this only fires when the SQL execution itself fails. The wrapped error is the lib/pq driver or Postgres error.

Source

Thrown at app/server/db/models.go:189

	var providers []*CustomProvider
	err := Conn.Select(&providers, `SELECT * FROM custom_providers WHERE org_id = $1 ORDER BY name`, orgId)
	return providers, err
}

func ListCustomProvidersForNames(orgId string, names []string) ([]*CustomProvider, error) {
	var providers []*CustomProvider
	query := `SELECT * FROM custom_providers WHERE org_id = $1 AND name = ANY($2) ORDER BY name`
	err := Conn.Select(&providers, query, orgId, pq.Array(names))
	return providers, err
}

func DeleteCustomProviders(tx *sqlx.Tx, orgId string, ids []string) error {
	if tx == nil {
		return fmt.Errorf("tx is nil")
	}
	_, err := tx.Exec(`DELETE FROM custom_providers WHERE org_id = $1 AND id = ANY($2)`, orgId, pq.Array(ids))
	if err != nil {
		return fmt.Errorf("error deleting custom providers: %v", err)
	}
	return nil
}

func UpsertModelPack(tx *sqlx.Tx, mp *ModelPack) error {
	if tx == nil {
		return fmt.Errorf("tx is nil")
	}
	const q = `
INSERT INTO model_sets (
	  org_id, name, description,
	  planner, coder, plan_summary,
	  builder, whole_file_builder, namer,
	  commit_msg, exec_status, context_loader
)
VALUES (
	  $1,$2,$3,
	  $4,$5,$6,

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read the wrapped error code (pq/pgerror) and verify the table and constraints (\d custom_providers)
  2. If the transaction is aborted from a prior failure, roll back and start a new tx
  3. Grant DELETE on custom_providers to the application role
  4. Remove/cascade dependent references before deleting providers
  5. Check logs for deadlock/timeout and retry the whole transaction

Example fix

// before
_, err := tx.Exec(`DELETE FROM custom_providers WHERE org_id = $1 AND id = ANY($2)`, orgId, pq.Array(ids))
if err != nil { return fmt.Errorf("error deleting custom providers: %v", err) }
// after
_, err := tx.Exec(`DELETE FROM custom_providers cp USING models m WHERE cp.id = m.provider_id AND ...`) // delete dependents first
_, err = tx.Exec(`DELETE FROM custom_providers WHERE org_id = $1 AND id = ANY($2)`, orgId, pq.Array(ids))
Defensive patterns

Strategy: try-catch

Validate before calling

func validateDeleteCustomProviders(tx *sqlx.Tx, orgId string, ids []string) error {
    if tx == nil { return errors.New("tx is nil") }
    if len(ids) == 0 { return errors.New("no provider ids given") }
    return nil
}

Type guard

func isForeignKeyViolation(err error) bool {
    var pgErr *pgconn.PgError
    return errors.As(err, &pgErr) && pgErr.Code == "23503"
}

Try / catch

if err := db.DeleteCustomProviders(tx, orgId, ids); err != nil {
    if isForeignKeyViolation(err) { return fmt.Errorf("providers still referenced: %w", err) }
    return err
}

Prevention

When it happens

Trigger: Dead/aborted transaction passed to DeleteCustomProviders; FK constraint referencing custom_providers rows; missing DELETE privilege; custom_providers table absent due to skipped migrations; malformed ids for pq.Array.

Common situations: Staging DB without latest migrations; production role without DELETE grants; a long-running tx hit a deadlock or statement_timeout; custom providers still referenced by models.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/9192def8e3ef44c2. Report an issue: GitHub.