{"record":{"id":"6c7966b9b16074f8","repo":"weaviate/weaviate","slug":"cutoffms-must-be-0-got-d","errorCode":null,"errorMessage":"cutoffMs must be > 0, got %d","messagePattern":"cutoffMs must be > 0, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"adapters/repos/db/index_async_checkpoint.go","lineNumber":201,"sourceCode":"// asyncCheckpointBroadcaster is the fan-out seam; tests substitute a stub.\ntype asyncCheckpointBroadcaster interface {\n\tLocalNodeName() string\n\tBroadcastCreateAsyncCheckpoint(ctx context.Context, shardNames []string, cutoffMs int64, createdAt time.Time) (successes, failures int)\n\tBroadcastDeleteAsyncCheckpoint(ctx context.Context, shardNames []string) (successes, failures int)\n\tBroadcastGetAsyncCheckpointStatus(ctx context.Context, shardNames []string) (statuses map[string][]replica.AsyncCheckpointNodeStatus, successes, failures int)\n}\n\n// CreateAsyncCheckpoints picks one createdAt for the whole fan-out so every\n// replica records the same convergence tie-breaker. Best-effort: per-shard\n// failures are logged, but the call returns nil and divergence reconciles\n// on the next cycle.\nfunc (i *Index) CreateAsyncCheckpoints(ctx context.Context, cutoffMs int64, shards []string) error {\n\treturn i.createAsyncCheckpoints(ctx, cutoffMs, shards, i.replicator)\n}\n\nfunc (i *Index) createAsyncCheckpoints(ctx context.Context, cutoffMs int64, shards []string, broadcaster asyncCheckpointBroadcaster) error {\n\tif cutoffMs <= 0 {\n\t\treturn fmt.Errorf(\"cutoffMs must be > 0, got %d\", cutoffMs)\n\t}\n\ttargets := i.resolveShardNames(shards)\n\tcreatedAt := time.Now().UTC()\n\n\tvar localSuccesses, localFailures atomic.Int64\n\teg, egCtx := enterrors.NewErrorGroupWithContextWrapper(i.logger, ctx)\n\teg.SetLimit(_NUMCPU)\n\tfor _, shardName := range targets {\n\t\tshardName := shardName\n\t\teg.Go(func() error {\n\t\t\tif err := i.createAsyncCheckpoint(egCtx, shardName, cutoffMs, createdAt); err != nil {\n\t\t\t\tlocalFailures.Add(1)\n\t\t\t\t// Debug, not Warn: \"shard not loaded here\" is expected for fan-out.\n\t\t\t\ti.logger.WithFields(logrus.Fields{\n\t\t\t\t\t\"action\": \"async_checkpoint_local\",\n\t\t\t\t\t\"op\":     \"create\",\n\t\t\t\t\t\"class\":  i.Config.ClassName,\n\t\t\t\t\t\"shard\":  shardName,","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/adapters/repos/db/index_async_checkpoint.go#L183-L219","documentation":"createAsyncCheckpoints validates its cutoffMs argument before doing any work and rejects non-positive values with \"cutoffMs must be > 0, got %d\". The cutoff (epoch milliseconds) defines which async-replication changes the checkpoint covers, so a zero/negative value is meaningless input.","triggerScenarios":"Calling Index.CreateAsyncCheckpoints(ctx, cutoffMs, shards) with cutoffMs == 0 or negative — e.g. an uninitialized int64, a failed time computation, or a caller passing 0 as a default.","commonSituations":"Application code computing a cutoff timestamp from an unset variable; marshaling bugs that zero out the timestamp; misuse of the internal API in tests/tools.","solutions":["Pass a positive cutoff in epoch milliseconds, e.g. time.Now().UTC().UnixMilli().","Validate the cutoff at the call site before invoking CreateAsyncCheckpoints.","If the cutoff was computed, log/inspect its derivation to find where it became zero."],"exampleFix":"// before\ncutoff := int64(0)\nidx.CreateAsyncCheckpoints(ctx, cutoff, shards) // rejected\n// after\ncutoff := time.Now().UTC().UnixMilli()\nidx.CreateAsyncCheckpoints(ctx, cutoff, shards)","handlingStrategy":"validation","validationCode":"if cutoffMs <= 0 {\n\treturn fmt.Errorf(\"cutoffMs must be positive, got %d\", cutoffMs)\n}","typeGuard":null,"tryCatchPattern":"if err := idx.CreateAsyncCheckpoints(ctx, cutoffMs, shards); err != nil {\n\tif strings.Contains(err.Error(), \"cutoffMs must be > 0\") {\n\t\treturn fmt.Errorf(\"caller bug: cutoff derived from %v\", cutoffSource)\n\t}\n\treturn err\n}","preventionTips":["Always derive cutoff from time.Now().UTC().UnixMilli()","Validate timestamps at the call site before passing int64 around","Avoid defaulting timestamps to zero values"],"tags":["validation","async-replication","checkpoint"],"backgroundTag":"invalid-argument","analyzedSha":"75aa4b6d11f8818305aafd4440b4e32794f7ca04","analyzedAt":"2026-09-04T14:58:20.392Z","contentChangedAt":"2026-09-04T14:58:20.392Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}