vitessio/vitess · error

Unknown GC state: %v

Error message

Unknown GC state: %v

What it means

generateGCTableName maps a TableGCState to its 3-character name-format code by scanning the gcStates map; if no entry's key matches the requested state, it fails with this error. It means the caller asked for a GC table name for a state that has no corresponding table-name code (e.g. an invalid or non-representable TableGCState value).

Source

Thrown at go/vt/schema/tablegc.go:88

	gcStatesTableHints[DropTableGCState] = InternalTableGCDropHint
	for _, gcState := range []TableGCState{HoldTableGCState, PurgeTableGCState, EvacTableGCState, DropTableGCState} {
		gcStates[string(gcState)] = gcState
		gcStates[gcState.TableHint().String()] = gcState
	}
}

// generateGCTableName creates a GC table name, based on desired state and time, and with optional preset UUID.
// If uuid is given, then it must be in GC-UUID format. If empty, the function auto-generates a UUID.
func generateGCTableName(state TableGCState, uuid string, t time.Time) (tableName string, err error) {
	for k, v := range gcStates {
		if v != state {
			continue
		}
		if len(k) == 3 && k != string(state) { // the "new" format
			return GenerateInternalTableName(k, uuid, t)
		}
	}
	return "", fmt.Errorf("Unknown GC state: %v", state)
}

// GenerateGCTableName creates a GC table name, based on desired state and time, and with random UUID
func GenerateGCTableName(state TableGCState, t time.Time) (tableName string, err error) {
	return generateGCTableName(state, "", t)
}

// AnalyzeGCTableName analyzes a given table name to see if it's a GC table, and if so, parse out
// its state, uuid, and timestamp
func AnalyzeGCTableName(tableName string) (isGCTable bool, state TableGCState, uuid string, t time.Time, err error) {
	// Try new naming format (e.g. `_vt_hld_6ace8bcef73211ea87e9f875a4d24e90_20200915120410_`):
	// The new naming format is accepted in v19, and actually _used_ in v20
	if isInternal, hint, uuid, t, err := AnalyzeInternalTableName(tableName); isInternal {
		gcState, ok := gcStates[hint]
		return ok, gcState, uuid, t, err
	}
	return false, state, uuid, t, nil
}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Pass one of the valid TableGCState values (e.g. TunableGCStates entries like hold/purge/drop states).
  2. Validate/parse the state with ParseGCLifecycle or check membership in gcStates before generating a name.
  3. Check where the state value originated (config/env/DB) for typos or empty strings.

Example fix

// before
state := schema.TableGCState("")
name, err := schema.GenerateGCTableName(state, time.Now())
// after
state := schema.HoldTableGCState
name, err := schema.GenerateGCTableName(state, time.Now())
Defensive patterns

Strategy: validation

Validate before calling

switch state {
case schema.HoldTableGCState, schema.PurgeTableGCState, schema.DropTableGCState, schema.EvacTableGCState:
    // ok
default:
    // reject before calling GenerateGCTableName
}

Type guard

func knownGCState(s schema.TableGCState) bool {
    for _, k := range schema.TunableGCStates {
        if k == s { return true }
    }
    return false
}

Try / catch

name, err := schema.GenerateGCTableName(state, now)
if err != nil {
    return fmt.Errorf("gc table name generation failed: %w", err)
}

Prevention

When it happens

Trigger: Calling GenerateGCTableName(state, t) or GenerateRenameStatementWithUUID with a TableGCState that is not one of the defined gcStates keys (e.g. a zero-value TableGCState("") or a corrupted/deserialized state).

Common situations: Deserializing a GC state from config or a DB column where the string didn't match enum values; constructing TableGCState from raw ints; passing an uninitialized state variable.

Related errors


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