plandex-ai/plandex · error

error deleting custom models: %v

Error message

error deleting custom models: %v

What it means

DeleteCustomModels wraps any failure of the batched DELETE on custom_models (scoped by org_id and id ANY($2)) with this message. It indicates the underlying PostgreSQL delete via sqlx Tx.Exec failed — not that zero rows were matched (deleting nothing is not an error). The wrapped %v is the driver/DB error (syntax, connection, constraint, or permission).

Source

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

func GetCustomModel(orgId, id string) (*CustomModel, error) {
	var model CustomModel
	err := Conn.Get(&model, `SELECT * FROM custom_models WHERE org_id = $1 AND id = $2`, orgId, id)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return &model, nil
}

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

func UpsertCustomProvider(tx *sqlx.Tx, p *CustomProvider) error {
	if tx == nil {
		return fmt.Errorf("tx is nil")
	}
	const q = `
INSERT INTO custom_providers (
	  org_id, name, base_url,
	  skip_auth, api_key_env_var, extra_auth_vars
)
VALUES (
	  $1,$2,$3,
	  $4,$5,$6
)
ON CONFLICT (org_id, name)

View on GitHub (pinned to e2d772072e)

Solutions

  1. Inspect the wrapped error (%v) for the exact pq/pgerror code and check the table exists (\d custom_models) / run migrations
  2. If the tx was aborted by an earlier statement, fix the first failing statement or use a fresh tx per operation
  3. Grant DELETE on custom_models to the app DB role
  4. For FK violations, delete dependent rows first or add ON DELETE CASCADE
  5. Retry once on transient connection errors before surfacing

Example fix

// before
_, err := tx.Exec(`DELETE FROM custom_models WHERE org_id = $1 AND id = ANY($2)`, orgId, pq.Array(ids))
// after
if len(ids) == 0 { return nil }
_, err := tx.Exec(`DELETE FROM custom_models WHERE org_id = $1 AND id = ANY($2)`, orgId, pq.Array(ids))
if err != nil {
    var pgErr *pgconn.PgError
    if errors.As(err, &pgErr) { log.Printf("delete custom_models failed: code=%s msg=%s", pgErr.Code, pgErr.Message) }
    return fmt.Errorf("error deleting custom models: %v", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

func validateDeleteCustomModels(tx *sqlx.Tx, orgId string, ids []string) error {
    if tx == nil { return errors.New("tx is nil") }
    if orgId == "" { return errors.New("orgId required") }
    for _, id := range ids { if id == "" { return errors.New("empty id") } }
    return nil
}

Type guard

func isPgError(err error) (*pgconn.PgError, bool) {
    var pgErr *pgconn.PgError
    ok := errors.As(err, &pgErr)
    return pgErr, ok
}

Try / catch

if err := validateDeleteCustomModels(tx, orgId, ids); err != nil { return err }
if err := db.DeleteCustomModels(tx, orgId, ids); err != nil {
    var pgErr *pgconn.PgError
    if errors.As(err, &pgErr) && (pgErr.Code == "40001" || pgErr.Code == "40P01") { return retryTx() }
    return err
}

Prevention

When it happens

Trigger: Calling DeleteCustomModels with a tx whose connection is dead or already rolled back; ids array malformed for pq.Array; a FK constraint (e.g. model references) blocking the DELETE; missing DELETE privilege or table custom_models missing (migrations not applied).

Common situations: Migrations out of date so custom_models doesn't exist; caller passed a tx that failed earlier and was aborted (Postgres 'current transaction is aborted'); DB role lacking DELETE grant in production; transient connection drops mid-transaction.

Related errors


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