micro/go-micro · error

model/postgres: create: %w

Error message

model/postgres: create: %w

What it means

Create executes an INSERT built from the schema and values. Duplicate-key/unique-constraint violations are translated to model.ErrDuplicateKey; any other INSERT failure is wrapped as "model/postgres: create" with the underlying driver error. So this error means the insert failed for a reason other than a duplicate key.

Source

Thrown at model/postgres/postgres.go:106

		return nil, model.ErrNotRegistered
	}
	return s, nil
}

func (d *postgresModel) Create(ctx context.Context, v interface{}) error {
	schema, err := d.schema(v)
	if err != nil {
		return err
	}
	fields := model.StructToMap(schema, v)
	cols, placeholders, values := buildInsert(schema, fields)
	query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", quoteIdent(schema.Table), cols, placeholders)
	_, err = d.db.ExecContext(ctx, query, values...)
	if err != nil {
		if strings.Contains(err.Error(), "duplicate key") || strings.Contains(err.Error(), "unique constraint") {
			return model.ErrDuplicateKey
		}
		return fmt.Errorf("model/postgres: create: %w", err)
	}
	return nil
}

func (d *postgresModel) Read(ctx context.Context, key string, v interface{}) error {
	schema, err := d.schema(v)
	if err != nil {
		return err
	}
	cols := columnList(schema)
	query := fmt.Sprintf("SELECT %s FROM %s WHERE %s = $1", cols, quoteIdent(schema.Table), quoteIdent(schema.Key))
	row := d.db.QueryRowContext(ctx, query, key)
	fields, err := scanRow(schema, row)
	if err != nil {
		return err
	}
	model.MapToStruct(schema, fields, v)
	return nil

View on GitHub (pinned to 24529f1404)

Solutions

  1. Unwrap the error to read the underlying Postgres message — it names the column/constraint at fault.
  2. Align the model schema with the actual table (run migrations) so columns and types match.
  3. Ensure required (NOT NULL) fields, including the key, are set on the struct before Create.
  4. Check connectivity/credentials if the cause is a connection or permission error.
  5. Handle model.ErrDuplicateKey separately if duplicates are expected business cases.

Example fix

// before
if err := store.Create(ctx, &user); err != nil {
    return err // opaque
}

// after
if err := store.Create(ctx, &user); err != nil {
    if errors.Is(err, model.ErrDuplicateKey) {
        return ErrEmailTaken
    }
    var pgErr *pgconn.PgError
    if errors.As(err, &pgErr) {
        log.Printf("insert failed: %s (column %s)", pgErr.Message, pgErr.ColumnName)
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate NOT NULL and key fields before Create
func insertable(v interface{}, required []string) error {
    rv := reflect.ValueOf(v)
    if rv.Kind() == reflect.Pointer {
        rv = rv.Elem()
    }
    for _, name := range required {
        if f := rv.FieldByName(name); !f.IsValid() || f.IsZero() {
            return fmt.Errorf("field %q required before insert", name)
        }
    }
    return nil
}

Try / catch

if err := store.Create(ctx, &user); err != nil {
    switch {
    case errors.Is(err, model.ErrDuplicateKey):
        return ErrAlreadyExists
    default:
        var pgErr *pgconn.PgError
        if errors.As(err, &pgErr) {
            log.Printf("create failed [%s]: %s", pgErr.Code, pgErr.Message)
        }
        return fmt.Errorf("create: %w", err)
    }
}

Prevention

When it happens

Trigger: Calling postgresModel.Create(ctx, v) when the INSERT fails due to a NOT NULL violation, type mismatch, missing column (schema/table drift), connection drop, permission denial, or invalid values (e.g. malformed JSON/UUID strings).

Common situations: Schema changed in the DB but the model wasn't updated (or vice versa), inserting nil into NOT NULL columns, wrong data types from unmarshaled payloads, transient network failures to Postgres.

Related errors


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