cayleygraph/cayley · error

cannot decode indexes: %v

Error message

cannot decode indexes: %v

What it means

readIndexesMeta reads the stored index metadata blob from the KV bucket and unmarshals it into []QuadIndex. If the stored bytes are not valid JSON or do not match the QuadIndex schema, the error is wrapped as "cannot decode indexes". A non-nil but empty list falls back to legacyQuadIndexes instead.

Source

Thrown at graph/kv/indexing.go:184

// readIndexesMeta read metadata about current indexes from the KV database.
// If no indexes are set, it returns a list of legacy indexes to preserve backward compatibility.
func (qs *QuadStore) readIndexesMeta(ctx context.Context) ([]QuadIndex, error) {
	tx, err := qs.db.Tx(ctx, false)
	if err != nil {
		return nil, err
	}
	defer tx.Close()
	tx = wrapTx(tx)
	val, err := tx.Get(ctx, keyMetaIndexes)
	if err == kv.ErrNotFound {
		return legacyQuadIndexes, nil
	} else if err != nil {
		return nil, err
	}
	var out []QuadIndex
	if err := json.Unmarshal(val, &out); err != nil {
		return nil, fmt.Errorf("cannot decode indexes: %v", err)
	} else if len(out) == 0 {
		return legacyQuadIndexes, nil
	}
	return out, nil
}

func (qs *QuadStore) resolveValDeltas(ctx context.Context, tx kv.Tx, deltas []graphlog.NodeUpdate, fnc func(i int, id uint64)) error {
	inds := make([]int, 0, len(deltas))
	keys := make([]kv.Key, 0, len(deltas))
	for i, d := range deltas {
		if iri, ok := d.Val.(quad.IRI); ok {
			if x, ok := qs.valueLRU.Get(string(iri)); ok {
				fnc(i, x.(uint64))
				continue
			}
		} else if d.Val == nil {
			fnc(i, 0)
			continue

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Back up, then reindex the store (delete the index metadata / re-run index building) so valid metadata is regenerated.
  2. Check the store was created by a compatible Cayley version; migrate via export/import if the format changed.
  3. Inspect the meta bucket value for the indexes key to confirm whether it is truncated or corrupt.
  4. If the directory is disposable, remove it and let the store initialize fresh with legacy indexes.

Example fix

// before: corrupt meta value
indexes_meta = "{\"wip\"" // truncated
// after: rebuild
// cayley dump --backup.db ... / cayley init on a fresh dir, then cayley load
Defensive patterns

Strategy: retry

Validate before calling

// sanity-check stored metadata at startup
var probe []kv.QuadIndex
if err := json.Unmarshal(val, &probe); err != nil || len(probe) == 0 {
    log.Println("index metadata invalid; reindexing recommended")
}

Try / catch

out, err := qs.Open(path)
if err != nil && strings.Contains(err.Error(), "cannot decode indexes") {
    return reindexStore(path) // backup, rebuild indexes, reopen
}

Prevention

When it happens

Trigger: Opening an existing kv-backed QuadStore (New -> readIndexesMeta) whose meta bucket contains a corrupted, truncated, or schema-incompatible indexes JSON value.

Common situations: Data directory written by an older Cayley version with a different index metadata format; disk corruption or an interrupted write leaving partial JSON; manually editing the database files.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/120fefb05f851221. Report an issue: GitHub.