vxcontrol/pentagi · error

failed to update provider: %w

Error message

failed to update provider: %w

What it means

UpdateProvider persists the provider row via pc.db.UpdateUserProvider (SQLC/PostgreSQL). Any database error — constraint violation, missing row, connection failure — is wrapped as "failed to update provider: %w". The provider was already validated and marshaled, so the failure is purely at the persistence layer.

Source

Thrown at backend/pkg/providers/providers.go:807

	}

	if err = config.Validate(); err != nil {
		return result, fmt.Errorf("invalid provider config: %w", err)
	}

	rawConfig, err := json.Marshal(config)
	if err != nil {
		return result, fmt.Errorf("failed to marshal provider config: %w", err)
	}

	result, err = pc.db.UpdateUserProvider(ctx, database.UpdateUserProviderParams{
		ID:     prvID,
		UserID: userID,
		Name:   string(prvname),
		Config: rawConfig,
	})
	if err != nil {
		return result, fmt.Errorf("failed to update provider: %w", err)
	}

	return result, nil
}

func (pc *providerController) DeleteProvider(
	ctx context.Context,
	userID int64,
	prvID int64,
) (database.Provider, error) {
	ctx, span := obs.Observer.NewSpan(ctx, obs.SpanKindInternal, "providers.DeleteProvider")
	defer span.End()

	result, err := pc.db.DeleteUserProvider(ctx, database.DeleteUserProviderParams{
		ID:     prvID,
		UserID: userID,
	})
	if err != nil {

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the wrapped error: sql.ErrNoRows means no provider with that ID for this user exists
  2. Verify prvID and userID match an existing row (query GetUserProvider first)
  3. Rename to a unique provider name if a unique constraint failed
  4. Check DB connectivity/pool health if the error is a connection error

Example fix

// before
prv, err := ctrl.UpdateProvider(ctx, userID, staleID, name, cfg) // fails after row deleted
// after
if _, err := ctrl.GetProvider(ctx, userID, name); err != nil {
    return fmt.Errorf("provider no longer exists, refresh UI: %w", err)
}
prv, err = ctrl.UpdateProvider(ctx, userID, prv.ID, name, cfg)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := ctrl.GetProvider(ctx, userID, prvname); err != nil {
    return fmt.Errorf("provider not found for user, nothing to update: %w", err)
}

Try / catch

result, err := ctrl.UpdateProvider(ctx, userID, prvID, name, cfg)
if err != nil {
    if errors.Is(err, sql.ErrNoRows) || strings.Contains(err.Error(), "failed to update provider") {
        return fmt.Errorf("provider %d no longer exists for user %d: %w", prvID, userID, err)
    }
    if isConstraintViolation(err) {
        return fmt.Errorf("provider name already taken: %w", err)
    }
    return err // transient DB issue: retry with backoff
}

Prevention

When it happens

Trigger: Calling UpdateProvider when the (ID, UserID) row does not exist, the DB is unreachable, the transaction fails, or a uniqueness constraint on provider name is violated.

Common situations: Updating a provider that was deleted in another tab (stale ID); wrong userID (multi-tenant mismatch); Postgres down or connection pool exhausted; duplicate provider name after a rename.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/45f1b410a2bcb99f. Report an issue: GitHub.