micro/go-micro · error

cannot create metadata index

Error message

cannot create metadata index

What it means

After successfully creating the table, initTable executes a CREATE INDEX statement for the metadata column and wraps failures with 'cannot create metadata index'. It means the GIN/btree index on the metadata JSONB column could not be created, even though the table itself exists.

Source

Thrown at store/postgres/pgx/pgx.go:101

		if err != nil {
			return nil, Queries{}, err
		}
	}

	return dbObj.conn, dbObj.tables[table], nil
}

func (s *sqlStore) initTable(database, table string) error {
	db := s.databases[database].conn

	_, err := db.Exec(s.options.Context, fmt.Sprintf(createTable, database, table))
	if err != nil {
		return errors.Wrap(err, "cannot create table")
	}

	_, err = db.Exec(s.options.Context, fmt.Sprintf(createMDIndex, table, database, table))
	if err != nil {
		return errors.Wrap(err, "cannot create metadata index")
	}

	_, err = db.Exec(s.options.Context, fmt.Sprintf(createExpiryIndex, table, database, table))
	if err != nil {
		return errors.Wrap(err, "cannot create expiry index")
	}

	s.databases[database].tables[table] = NewQueries(database, table)

	return nil
}

func (s *sqlStore) initDB(database string) error {
	if len(s.options.Nodes) == 0 {
		s.options.Nodes = []string{"postgresql://root@localhost:26257?sslmode=disable"}
	}

	source := s.options.Nodes[0]

View on GitHub (pinned to 24529f1404)

Solutions

  1. Grant INDEX/CREATE privilege: GRANT CREATE ON SCHEMA public TO <user> (or table owner must run the index DDL).
  2. Check the wrapped PostgreSQL error for the specific reason.
  3. Retry initialization if a concurrent instance held locks during index creation.
  4. Create the index manually with the exact definition the store expects.
  5. Confirm required extensions (e.g. for JSONB GIN indexes) are available.

Example fix

// before
// db.Exec(createMDIndex...) fails with permission denied
// after
GRANT CREATE ON SCHEMA public TO micro_user;
// or pre-create index manually before app start
Defensive patterns

Strategy: validation

Validate before calling

// before init
var canIdx bool
conn.QueryRow(ctx, "SELECT has_schema_privilege(current_user, 'public', 'CREATE')").Scan(&canIdx)
// verify extension support for the index method, e.g.:
// SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname='...');

Try / catch

if err := store.Init(); err != nil {
	var pgErr *pgconn.PgError
	if errors.As(err, &pgErr) && pgErr.Code == "42P17" || pgErr.Code == "42501" {
		// pre-create index manually or fix privileges, then retry
	}
	return err
}

Prevention

When it happens

Trigger: First access to an uninitialized table where the CREATE INDEX for metadata fails: missing table (created concurrently?), insufficient privileges to create indexes, shared lock contention, or DB not supporting the index type.

Common situations: DB user can CREATE TABLE but not INDEX; concurrent store instances racing on initialization causing transient lock timeouts; managed Postgres restricting certain index types (e.g. no GIN extension).

Related errors


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