micro/go-micro · error

ErrDuplicateKey

ErrDuplicateKey

Error message

duplicate key

What it means

model.ErrDuplicateKey is returned when creating a record whose primary key already exists in the store. The model package enforces key uniqueness on Create and surfaces this sentinel so callers can detect conflicts.

Source

Thrown at model/model.go:13

// Package model is an interface for structured data storage with schema awareness.
package model

import (
	"context"
	"errors"
)

var (
	// ErrNotFound is returned when a record doesn't exist.
	ErrNotFound = errors.New("not found")
	// ErrDuplicateKey is returned when a record with the same key already exists.
	ErrDuplicateKey = errors.New("duplicate key")
	// ErrNotRegistered is returned when a table has not been registered.
	ErrNotRegistered = errors.New("table not registered")
	// DefaultModel is the default model.
	DefaultModel Model = NewModel()
)

// Model is a structured data storage interface.
type Model interface {
	// Init initializes the model.
	Init(...Option) error
	// Register registers a struct type as a table.
	Register(v interface{}, opts ...RegisterOption) error
	// Create inserts a new record. Returns ErrDuplicateKey if key exists.
	Create(ctx context.Context, v interface{}) error
	// Read retrieves a record by key into v. Returns ErrNotFound if missing.
	Read(ctx context.Context, key string, v interface{}) error
	// Update modifies an existing record. Returns ErrNotFound if missing.
	Update(ctx context.Context, v interface{}) error

View on GitHub (pinned to 24529f1404)

Solutions

  1. Check errors.Is(err, model.ErrDuplicateKey) and treat it as upsert/already-exists where appropriate.
  2. Delete the existing record first or use an update/replace path instead of Create.
  3. Add a unique client/node ID (node.Id) to the key so concurrent registrars don't collide.
  4. Clean the store between test runs to avoid leftovers triggering duplicates.

Example fix

// before
err := m.Create("services", rec) // fails if key exists
// after
err := m.Create("services", rec)
if errors.Is(err, model.ErrDuplicateKey) {
    err = m.Update("services", rec)
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

func isDuplicate(err error) bool { return errors.Is(err, model.ErrDuplicateKey) }

Try / catch

err := m.Create("services", rec)
if errors.Is(err, model.ErrDuplicateKey) {
    return m.Update("services", rec) // upsert semantics
}
return err

Prevention

When it happens

Trigger: Calling Create twice with the same service name/key without deleting the first; two nodes racing to register the same key concurrently; re-running an idempotent-by-intent registration that isn't actually idempotent.

Common situations: Restart loops re-registering services; leader-election code where two instances briefly both act as leader; test suites not cleaning the store between runs.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/d05bd36bfa8dc90d. Report an issue: GitHub.