temporalio/temporal · error · Unavailable

rowsAffected returned error when initializing DLQ metadata

Error message

rowsAffected returned error when initializing DLQ metadata  %v: %v

What it means

Thrown by initializeDLQMetadata in the SQL queue store after an INSERT of DLQ metadata succeeds, but result.RowsAffected() returns a driver error. Temporal expects exactly one metadata row to be created during DLQ initialization; if the driver cannot report affected-row counts, initialization cannot be verified and fails. This usually signals a database driver that does not support RowsAffected for this statement.

Source

Thrown at common/persistence/sql/queue.go:368

) error {
	_, err := q.DB.SelectFromQueueMetadata(ctx, sqlplugin.QueueMetadataFilter{
		QueueType: q.getDLQTypeFromQueueType(),
	})
	switch err {
	case nil:
		return nil
	case sql.ErrNoRows:
		result, err := q.DB.InsertIntoQueueMetadata(ctx, &sqlplugin.QueueMetadataRow{
			QueueType:    q.getDLQTypeFromQueueType(),
			Data:         blob.Data,
			DataEncoding: blob.EncodingType.String(),
		})
		if err != nil {
			return serviceerror.NewUnavailablef("initializeDLQMetadata operation failed. Error %v", err)
		}
		rowsAffected, err := result.RowsAffected()
		if err != nil {
			return fmt.Errorf("rowsAffected returned error when initializing DLQ metadata  %v: %v", q.queueType, err)
		}
		if rowsAffected != 1 {
			return fmt.Errorf("rowsAffected returned %v DLQ metadata instead of one", rowsAffected)
		}
		return nil
	default:
		return err
	}
}

func newQueueRow(
	queueType persistence.QueueType,
	messageID int64,
	blob *commonpb.DataBlob,
) sqlplugin.QueueMessageRow {

	return sqlplugin.QueueMessageRow{
		QueueType:       queueType,

View on GitHub (pinned to bde624efd1)

Solutions

  1. Check that the SQL driver in use (go-sql-driver/mysql, lib/pq, sqlite) supports RowsAffected on INSERT — upgrade the driver to the latest version.
  2. Inspect the wrapped driver error (%v at the end of the message) for the root cause (connection reset, unsupported method).
  3. Verify the database backend is one of the officially supported ones (MySQL, PostgreSQL, SQLite).
  4. Retry queue Init; if transient connection issues caused it, the next attempt may find the row already inserted and return nil early.
Defensive patterns

Strategy: retry

Try / catch

if err := q.Init(); err != nil {
    if strings.Contains(err.Error(), "rowsAffected returned error") {
        // transient driver issue; retry with backoff
    }
    return err
}

Prevention

When it happens

Trigger: Init() -> initializeDLQMetadata on a queue with no existing metadata row: SELECT returns sql.ErrNoRows, INSERT succeeds, then result.RowsAffected() itself returns an error from the SQL driver.

Common situations: Using a database or driver whose RowsAffected implementation is unsupported for INSERT statements; driver/connection issues right after the insert; non-MySQL/Postgres backends with partial driver support.

Related errors


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