vitessio/vitess · error

failed to marshal pk fields and value into query result: %s

Error message

failed to marshal pk fields and value into query result: %s

What it means

This error is thrown during VReplication copy when marshalling the primary-key fields and last copied row into a querypb.QueryResult (via prototext.Marshal) fails. The marshalled result is bound as the :lastpk bind variable in the next copy batch query, so a marshal failure means the copy-continuation state cannot be built. It is effectively an internal/serialization error, since querypb types normally marshal cleanly.

Source

Thrown at go/vt/vttablet/tabletmanager/vreplication/vcopier_atomic.go:205

				"insert into _vt.copy_state (lastpk, vrepl_id, table_name) values (%a, %s, %s)", ":lastpk",
				strconv.Itoa(int(vc.vr.id)),
				encodeString(tableName),
			)
			addLatestCopyState := buf.ParsedQuery()
			copyWorkQueue.open(addLatestCopyState, pkfields, tablePlan)
		}
		// When rowstreamer has finished streaming all rows, we get a callback with empty rows.
		if len(resp.Rows) == 0 {
			return nil
		}
		// Get the last committed pk into a loggable form.
		lastpkbuf, merr := prototext.Marshal(&querypb.QueryResult{
			Fields: pkfields,
			Rows:   []*querypb.Row{lastpk},
		})

		if merr != nil {
			return fmt.Errorf("failed to marshal pk fields and value into query result: %s", merr.Error())
		}
		lastpkbv = map[string]*querypb.BindVariable{
			"lastpk": {
				Type:  sqltypes.VarBinary,
				Value: lastpkbuf,
			},
		}
		log.Info(fmt.Sprintf("copying table %s with lastpk %v", tableName, lastpkbv))
		// Prepare a vcopierCopyTask for the current batch of work.
		currCh := make(chan *vcopierCopyTaskResult, 1)

		if parallelism > 1 {
			resp = resp.CloneVT()
		}
		currT := newVCopierCopyTask(newVCopierCopyTaskArgs(resp.Rows, resp.Lastpk))

		// Send result to the global resultCh and currCh. resultCh is used by
		// the loop to return results to VStreamRows. currCh will be used to

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Inspect the %s detail (the underlying merr) in the error message to identify which field/value failed to marshal
  2. Verify the source table's primary key columns exist and their types match what vreplication discovered (check SHOW CREATE TABLE on source vs the copied schema)
  3. Retry the workflow; if reproducible, collect the exact table/columns and file a Vitess issue with the marshal error text
  4. Check the Vitess version for known vcopier serialization bugs and upgrade to a patched release
Defensive patterns

Strategy: validation

Validate before calling

// Before starting/retrying a copy workflow, verify the source PK schema is discoverable
cols := vtctldClient.GetWorkflow(workflowName).CopyState[table]
if len(cols.PKColumns) == 0 {
    return fmt.Errorf("table %s has no discoverable primary key; fix schema before copy", table)
}

Try / catch

err := vtctldClient.WorkflowStart(...)
if err != nil && strings.Contains(err.Error(), "failed to marshal pk fields") {
    // inspect merr detail, verify source schema, then retry
    log.Error("copy marshal failure", slog.Any("error", err))
}

Prevention

When it happens

Trigger: prototext.Marshal fails on the constructed &querypb.QueryResult{Fields: pkfields, Rows: []*querypb.Row{lastpk}} in vcopier's copy loop — e.g. malformed or nil field/row contents fed into the query result used for the lastpk bind variable.

Common situations: Corrupted or empty source table schema/primary key info during MoveTables/VCopy; a source row whose field descriptors do not match the row data; bugs in custom or filtered copy flows supplying inconsistent pkfields.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/2ca332272eb0de72. Report an issue: GitHub.