{"record":{"id":"6b81b084560afc0e","repo":"cayleygraph/cayley","slug":"cannot-get-horizon-value-v","errorCode":null,"errorMessage":"cannot get horizon value: %v","messagePattern":"cannot get horizon value: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graph/kv/indexing.go","lineNumber":240,"sourceCode":"\t\t\tcontinue\n\t\t}\n\t\tind := inds[i]\n\t\tid, _ := binary.Uvarint(b)\n\t\td := &deltas[ind]\n\t\tif iri, ok := d.Val.(quad.IRI); ok && id != 0 {\n\t\t\tqs.valueLRU.Put(string(iri), uint64(id))\n\t\t}\n\t\tfnc(ind, uint64(id))\n\t}\n\treturn nil\n}\n\nfunc (qs *QuadStore) getMetaIntTx(ctx context.Context, tx kv.Tx, key string) (int64, error) {\n\tval, err := tx.Get(ctx, metaBucket.AppendBytes([]byte(key)))\n\tif err == kv.ErrNotFound {\n\t\treturn 0, err\n\t} else if err != nil {\n\t\treturn 0, fmt.Errorf(\"cannot get horizon value: %v\", err)\n\t}\n\treturn int64(binary.LittleEndian.Uint64(val)), nil\n}\n\nfunc (qs *QuadStore) incMetaInt(ctx context.Context, tx kv.Tx, key string, n int64) (int64, error) {\n\tif n == 0 {\n\t\treturn 0, nil\n\t}\n\tv, err := qs.getMetaIntTx(ctx, tx, key)\n\tif err != nil && err != kv.ErrNotFound {\n\t\treturn 0, fmt.Errorf(\"cannot get %s: %v\", key, err)\n\t}\n\tstart := v\n\tv += n\n\n\tbuf := make([]byte, 8) // bolt needs all slices available on Commit\n\tbinary.LittleEndian.PutUint64(buf, uint64(v))\n","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/graph/kv/indexing.go#L222-L258","documentation":"getMetaIntTx fetches a 8-byte little-endian integer from the meta bucket within a transaction. ErrNotFound is normal (treated as 0), but any other storage error is wrapped as \"cannot get horizon value\". The name references the horizon/size counters kept in the meta bucket, despite the generic key parameter.","triggerScenarios":"Any kv transaction Get on a meta key failing with a storage-level error (I/O error, closed DB, bolt/leveldb failure) during incMetaInt-driven writes such as size increments or ID generation.","commonSituations":"Underlying KV database file locked or corrupted; disk I/O errors; transaction used after the store was closed; backend-specific failures surfaced through kv.Tx.Get.","solutions":["Inspect the wrapped inner error (%v) to identify the backend failure and fix that root cause.","Verify the database file is accessible and not locked by another process or opened with conflicting options.","Check disk health/space and file permissions on the KV database.","Restart the process and reopen the store; if corruption persists, restore from backup and reindex."],"exampleFix":"// before: store closed while goroutines still write\nqs.Close(); qs.incSize(ctx, 1) // cannot get horizon value: tx on closed db\n// after\n// ensure all writers finish before Close, or reopen the store before writing\nqs2, err := kv.New(...); qs2.incSize(ctx, 1)","handlingStrategy":"retry","validationCode":"if qs == nil || closed {\n    return fmt.Errorf(\"store must be open before meta operations\")\n}","typeGuard":null,"tryCatchPattern":"n, err := qs.incSize(ctx, 1)\nif err != nil {\n    if errors.Is(err, kv.ErrNotFound) {\n        n = 0 // first increment\n    } else if strings.Contains(err.Error(), \"cannot get\") {\n        // inspect wrapped backend error, reopen store or fail fast\n        return reopenAndRetry()\n    }\n}","preventionTips":["Close the store only after all writers finish.","Monitor disk health and space on KV database volumes.","Do not open the same database from multiple processes with incompatible locking."],"tags":["kv-store","meta","storage-error"],"backgroundTag":"database-query-failed","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}