vitessio/vitess · error

lastpk for table %s has no fields defined

Error message

lastpk for table %s has no fields defined

What it means

uvstreamer.buildTablePlan validates every incoming TableLastPK: if a lastpk is present but carries an empty Fields list, the checkpoint is malformed and cannot be mapped to columns, so the unified vstreamer refuses to build the table plan.

Source

Thrown at go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go:154

		throttlerApp: throttlerApp,
		options:      options,
	}

	return uvs
}

// buildTablePlan identifies the tables for the copy phase and creates the plans which consist of the lastPK seen
// for a table and its Rule (for filtering purposes by the vstreamer engine)
// it can be called
//
//	the first time, with just the filter and an empty pos
//	during a restart, with both the filter and list of TableLastPK from the vgtid
func (uvs *uvstreamer) buildTablePlan() error {
	uvs.plans = make(map[string]*tablePlan)
	tableLastPKs := make(map[string]*binlogdatapb.TableLastPK)
	for _, tablePK := range uvs.inTablePKs {
		if tablePK != nil && tablePK.Lastpk != nil && len(tablePK.Lastpk.Fields) == 0 {
			return fmt.Errorf("lastpk for table %s has no fields defined", tablePK.TableName)
		}
		tableLastPKs[tablePK.TableName] = tablePK
	}
	tables := uvs.se.GetSchema()
	for range tables {
		for _, rule := range uvs.filter.Rules {
			if !strings.HasPrefix(rule.Match, "/") {
				_, ok := tables[rule.Match]
				if !ok {
					return fmt.Errorf("table %s is not present in the database", rule.Match)
				}
			}
		}
	}

	// Set of tables to copy during the copy phase. Only if we need to copy
	// specific tables, else keep it nil if we need to copy every table.
	var tablesToCopySet sets.Set[string]

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Inspect the checkpointed TableLastPK for the named table; the lastpk proto must include both Fields and Rows.
  2. Reset the copy phase / clear the bad TableLastPK entry and let the streamer regenerate the checkpoint from live schema.
  3. If produced by an upgrade, check release notes for checkpoint-format migration and re-initialize the workflow.
Defensive patterns

Strategy: validation

Validate before calling

for _, tp := range tablePKs {
    if tp.Lastpk != nil && len(tp.Lastpk.Fields) == 0 {
        return fmt.Errorf("rejecting malformed lastpk for %s: fields empty", tp.TableName)
    }
}

Try / catch

err := uvstream(ctx, filter, tablePKs)
if err != nil && strings.Contains(err.Error(), "has no fields defined") {
    // checkpoint is malformed: clear it and restart copy phase
    clearTableLastPK(workflow, errTableName)
    restart(ctx)
}

Prevention

When it happens

Trigger: VStream called with a vgtid/tablePKs list where a table's Lastpk is non-nil but Lastpk.Fields is empty — a corrupt or hand-constructed checkpoint.

Common situations: Restarts where a workflow was migrated from an older format, checkpoints written by buggy/older code, or manual construction of TableLastPK when calling VStream APIs directly.

Related errors


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