{"record":{"id":"4da71075fe389aef","repo":"canopy-network/canopy","slug":"rollback-target-height-must-be-1","errorCode":null,"errorMessage":"rollback target height must be >= 1","messagePattern":"rollback target height must be >= 1","errorType":"error_code","errorClass":"ErrCommitDB","httpStatus":null,"severity":"error","filePath":"store/store.go","lineNumber":331,"sourceCode":"\tkeys := make([][]byte, 0, len(s.ss.txn.ops))\n\tfor _, op := range s.ss.txn.ops {\n\t\tkeys = append(keys, bytes.Clone(op.key))\n\t}\n\ts.ss.txn.l.Unlock()\n\treturn s.Indexer.indexStateChangeKeys(version, keys)\n}\n\n// Rollback rewinds the store to a previous version (height).\n//\n// It removes all versioned entries above targetVersion, rebuilds the latest state\n// view from historical state at targetVersion, and resets the latest commit pointer.\n// NOTE: Rollback is an offline maintenance operation and must only run while the node is stopped.\nfunc (s *Store) Rollback(targetVersion uint64) lib.ErrorI {\n\tif s.isTxn {\n\t\treturn ErrCommitDB(fmt.Errorf(\"rollback is not supported for nested transactions\"))\n\t}\n\tif targetVersion == 0 {\n\t\treturn ErrCommitDB(fmt.Errorf(\"rollback target height must be >= 1\"))\n\t}\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tcurrentVersion := s.version\n\tif targetVersion > currentVersion {\n\t\treturn ErrCommitDB(fmt.Errorf(\"rollback target height %d exceeds current height %d\", targetVersion, currentVersion))\n\t}\n\tif targetVersion == currentVersion {\n\t\treturn nil\n\t}\n\n\tsnapshot := s.db.NewSnapshot()\n\tdefer snapshot.Close()\n\n\t// Ensure the target commit exists so we can repoint the latest commit id.\n\ttargetReader := NewVersionedStore(snapshot, nil, targetVersion)\n\ttargetTx := NewTxn(targetReader, nil, nil, false, false, true)","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/store/store.go#L313-L349","documentation":"Rollback requires a positive target height: version 0 does not exist as a rollback destination (state versions start at 1). Passing targetVersion == 0 is rejected with this error before any database work is done.","triggerScenarios":"Calling Store.Rollback(0), e.g. a misconfigured CLI flag or a variable that defaulted to zero because the target height was never parsed/loaded from config.","commonSituations":"Rollback command invoked with a missing --height flag defaulting to 0; a script computing target height from an unset environment variable; off-by-one logic mapping 'genesis' to version 0.","solutions":["Pass a target height >= 1, typically the last known good block height","Check the CLI/config parsing that supplies targetVersion and guard against zero values before calling Rollback","If the intent is 'rewind one block', compute currentVersion - 1 instead of using 0"],"exampleFix":"// before\nif err := store.Rollback(targetHeight); err != nil {...} // targetHeight==0\n// after\nif targetHeight < 1 {\n    return fmt.Errorf(\"--height must be provided (>=1)\")\n}\nif err := store.Rollback(targetHeight); err != nil {...}","handlingStrategy":"validation","validationCode":"if targetVersion < 1 {\n    return fmt.Errorf(\"rollback target height must be >= 1, got %d\", targetVersion)\n}","typeGuard":null,"tryCatchPattern":"if err := st.Rollback(h); err != nil {\n    if strings.Contains(err.Error(), \"must be >= 1\") {\n        return fmt.Errorf(\"invalid --height flag: must supply a block height >= 1\")\n    }\n    return err\n}","preventionTips":["Validate CLI/config height flags before invoking Rollback","Make the height flag required (no silent zero default)","Map 'genesis' explicitly to version 1 if that semantic is needed"],"tags":["store","rollback","argument"],"backgroundTag":"argument-out-of-range","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}