zincsearch/zincsearch · error · errors.Error

runtime_exception

runtime_exception

Error message

second shard not found

What it means

GetWriter resolves a shard by numeric ID: if no explicit shardID is passed, it falls back to GetLatestShardID(). The error is thrown when the resolved shard id is out of range (>= shard count or negative), so no second shard can be located for the write/dual-write path. It surfaces from callers like CheckShards, GetWriters and WriteToShard(Rollback).

Source

Thrown at pkg/core/index_shards.go:161

	s.root.lock.Unlock()

	// store update
	if err := storeIndex(s.root); err != nil {
		return err
	}
	return s.openWriter(s.GetLatestShardID())
}

// GetWriter return the newest shard writer or special shard writer
func (s *IndexShard) GetWriter(shardID ...int64) (*bluge.Writer, error) {
	var id int64
	if len(shardID) == 1 {
		id = shardID[0]
	} else {
		id = s.GetLatestShardID()
	}
	if id >= s.GetShardNum() || id < 0 {
		return nil, errors.New(errors.ErrorTypeRuntimeException, "second shard not found")
	}
	s.lock.RLock()
	secondShard := s.shards[id]
	s.lock.RUnlock()

	secondShard.lock.RLock()
	w := secondShard.writer
	secondShard.lock.RUnlock()
	if w != nil {
		return w, nil
	}

	// open writer
	if err := s.openWriter(id); err != nil {
		return nil, err
	}

	// check WAL

View on GitHub (pinned to dd2f8afd65)

Solutions

  1. Check the shardID argument you pass to GetWriter/WriteToShard; it must satisfy 0 <= id < index.GetShardNum().
  2. Re-run CheckShards to compare the on-disk shard count with the index metadata and repair mismatches (recreate missing shards or fix ShardNum).
  3. If GetLatestShardID() is the source, reinitialize the index or fix the metadata so latest shard ID is in range.
  4. Restore consistent index state from a good snapshot rather than manually editing shard files.
  5. Catch the error at the write path and fall back to shard id 0 or recreate the index if data integrity allows.

Example fix

// before
w, err := idx.GetWriter(7) // only 4 shards exist
// after
if shardID < 0 || shardID >= idx.GetShardNum() {
    return fmt.Errorf("shard %d out of range (0..%d)", shardID, idx.GetShardNum()-1)
}
w, err := idx.GetWriter(shardID)
Defensive patterns

Strategy: validation

Validate before calling

func safeShardID(idx *core.Index, id uint64) bool {
    return id < uint64(idx.GetShardNum())
}
// call only if safeShardID(idx, shardID) before GetWriter(shardID)

Type guard

func shardInRange(id int, shardNum int) bool { return id >= 0 && id < shardNum }

Try / catch

w, err := idx.GetWriter(shardID)
if err != nil && strings.Contains(err.Error(), "second shard not found") {
    // repair index state or fall back to a valid shard
    w, err = idx.GetWriter(0)
}

Prevention

When it happens

Trigger: Calling GetWriter/GetWriters/WriteToShard with an explicit shardID that does not exist (id >= GetShardNum() or id < 0), or GetLatestShardID() returning a stale/invalid id (e.g. index metadata says fewer shards than actually exist after a corrupted or partial shard load).

Common situations: Manually deleting shard directories or restoring index data from a backup that mismatches metadata; passing a shard id copied from a different index; concurrent shard-resize operations racing with writers; importing an index whose ShardNum in metadata was edited by hand.

Related errors


AI-assisted analysis of zincsearch/zincsearch@dd2f8afd65 (2026-09-03). Data as JSON: /api/errors/e9687415f25037eb. Report an issue: GitHub.