micro/go-micro · error

model/postgres: update: %w

Error message

model/postgres: update: %w

What it means

Update builds an UPDATE ... WHERE key = $n statement from the struct's non-key fields and executes it. Any SQL failure is wrapped as "model/postgres: update"; additionally, if the statement succeeds but affects zero rows, the method returns model.ErrNotFound, meaning no record matched the key.

Source

Thrown at model/postgres/postgres.go:141

	model.MapToStruct(schema, fields, v)
	return nil
}

func (d *postgresModel) Update(ctx context.Context, v interface{}) error {
	schema, err := d.schema(v)
	if err != nil {
		return err
	}
	fields := model.StructToMap(schema, v)
	key := model.KeyValue(schema, v)
	setClauses, values := buildUpdate(schema, fields)
	values = append(values, key)
	paramIdx := len(values)
	query := fmt.Sprintf("UPDATE %s SET %s WHERE %s = $%d",
		quoteIdent(schema.Table), setClauses, quoteIdent(schema.Key), paramIdx)
	result, err := d.db.ExecContext(ctx, query, values...)
	if err != nil {
		return fmt.Errorf("model/postgres: update: %w", err)
	}
	n, _ := result.RowsAffected()
	if n == 0 {
		return model.ErrNotFound
	}
	return nil
}

func (d *postgresModel) Delete(ctx context.Context, key string, v interface{}) error {
	schema, err := d.schema(v)
	if err != nil {
		return err
	}
	query := fmt.Sprintf("DELETE FROM %s WHERE %s = $1", quoteIdent(schema.Table), quoteIdent(schema.Key))
	result, err := d.db.ExecContext(ctx, query, key)
	if err != nil {
		return fmt.Errorf("model/postgres: delete: %w", err)
	}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Verify the record exists (Read by key) before/after Update; handle model.ErrNotFound for stale IDs.
  2. Unwrap the error to see the driver's message and fix the offending column/type.
  3. Ensure the key field is set and matches the stored primary key exactly (type and value).
  4. Run migrations if the table schema drifted from the model definition.
  5. Check connectivity and transaction state if the cause is a connection error.

Example fix

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

// after
if err := store.Update(ctx, &user); err != nil {
    if errors.Is(err, model.ErrNotFound) {
        return http.StatusNotFound
    }
    return fmt.Errorf("update user %s: %w", user.ID, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm the row exists before Update
var exists bool
if err := db.QueryRow(
    "SELECT EXISTS (SELECT 1 FROM users WHERE id = $1)", user.ID,
).Scan(&exists); err != nil {
    return err
}
if !exists {
    return model.ErrNotFound
}

Try / catch

if err := store.Update(ctx, &user); err != nil {
    if errors.Is(err, model.ErrNotFound) {
        return ErrUserGone // zero rows affected: key doesn't match any row
    }
    var pgErr *pgconn.PgError
    if errors.As(err, &pgErr) {
        log.Printf("update failed [%s]: %s", pgErr.Code, pgErr.Message)
    }
    return fmt.Errorf("update: %w", err)
}

Prevention

When it happens

Trigger: Calling postgresModel.Update(ctx, v) where the SQL errors (type mismatch, NOT NULL violation, schema drift, connection issue) — wrapped error; or where the key field of v doesn't match any existing row — ErrNotFound variant.

Common situations: Updating a record that was deleted concurrently, stale client caches holding old IDs, PATCH handlers sending structs with wrong types, or mismatched key type between model schema and table column.

Related errors


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