temporalio/temporal · error

%v rows were affected instead of 1

Error message

%v rows were affected instead of 1

What it means

After an UpdateTaskQueue SQL statement executes, the code checks result.RowsAffected() and requires exactly 1 row to be modified. If the statement affected 0 or multiple rows, it returns this error, indicating the assumed single-row update invariant was violated (usually the task queue row did not exist or a range/condition matched unexpectedly).

Source

Thrown at common/persistence/sql/task_queues.go:122

		); err != nil {
			return err
		}
		result, err := tx.UpdateTaskQueues(ctx, &sqlplugin.TaskQueuesRow{
			RangeHash:    tqHash,
			TaskQueueID:  tqId,
			RangeID:      request.RangeID,
			Data:         request.TaskQueueInfo.Data,
			DataEncoding: request.TaskQueueInfo.EncodingType.String(),
		}, m.version)
		if err != nil {
			return err
		}
		rowsAffected, err := result.RowsAffected()
		if err != nil {
			return err
		}
		if rowsAffected != 1 {
			return fmt.Errorf("%v rows were affected instead of 1", rowsAffected)
		}
		resp = &persistence.UpdateTaskQueueResponse{}
		return nil
	})
	return resp, err
}

func (m *taskQueueStore) ListTaskQueue(
	ctx context.Context,
	request *persistence.ListTaskQueueRequest,
) (*persistence.InternalListTaskQueueResponse, error) {
	pageToken := taskQueuePageToken{MinTaskQueueId: minTaskQueueId}
	if request.PageToken != nil {
		if err := gobDeserialize(request.PageToken, &pageToken); err != nil {
			return nil, serviceerror.NewInternalf("error deserializing page token: %v", err)
		}
	}
	var err error

View on GitHub (pinned to bde624efd1)

Solutions

  1. Verify the task queue exists (ListTaskQueue/DescribeTaskQueue) before updating and that namespaceID/name are correct.
  2. Check for concurrent operations racing on the same task queue row; retry the operation or re-fetch rangeID after the conflict.
  3. Confirm rangeID/range conditions passed to UpdateTaskQueue match current shard state; reload shard state if stale.
  4. Inspect the DB row directly to see whether the expected row exists and whether the UPDATE WHERE clause could match multiple rows.

Example fix

// before
resp, err := p.UpdateTaskQueue(ctx, req) // rowsAffected == 0
// after
existing, err := p.GetTaskQueue(ctx, getReq)
if err != nil { return err }
resp, err := p.UpdateTaskQueue(ctx, req) // with valid rangeID from existing
Defensive patterns

Strategy: retry

Validate before calling

// pre-check the queue exists and rangeID is current
_, err := persistenceStore.GetTaskQueue(ctx, &persistence.GetTaskQueueRequest{NamespaceID: nsID, Name: tqName, TaskType: taskType})

Try / catch

resp, err := store.UpdateTaskQueue(ctx, req)
if err != nil && strings.Contains(err.Error(), "rows were affected") {
    // re-fetch rangeID / shard state and retry once
    return retryWithFreshRangeID(ctx, req)
}
return err

Prevention

When it happens

Trigger: Calling persistence.UpdateTaskQueue when the task_queues row for the given (namespaceID, name, rangeID/kind) does not exist, or when a conditional UPDATE whose WHERE clause matches more than one row is executed.

Common situations: Task queue deleted concurrently by a reaper while being updated, stale rangeID causing the optimistic-condition UPDATE to match nothing, DB replication/divergence, running against a schema where the unique key assumptions don't hold.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/455098f24cdb3016. Report an issue: GitHub.