Node fails to start. Unrecoverable error

Unfortunately, the --fast flag doesn’t help :frowning:

root@PC3 ~/g/bin# ~/go/bin/write-hashtbl --fast  /mnt/Storj-5_18WB5/Storj_15/storage/hashstore/12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S/s1
...
Processing /mnt/Storj-5_18WB5/Storj_15/storage/hashstore/12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S/s1/ff/log-0000000000001aff-00000000...
hashstore: put:{key:14b80c184331bb7bdfeb7f87773fc7c04b465eab2ab2b5d3ff3150969cab36f5 offset:1068279680 log:5376 length:5632 created:20163 (2025-03-16) expires:0 (1970-01-01) trash:false} != exist:{key:14b80c184331bb7bdfeb7f87773fc7c04b465eab2ab2b5d3ff3150969cab36f5 offset:1068285376 log:5376 length:5632 created:20163 (2025-03-16) expires:0 (1970-01-01) trash:false}: hashstore: collision detected
        storj.io/storj/storagenode/hashstore.(*HashTbl).insertLocked:411
        storj.io/storj/storagenode/hashstore.(*HashTblConstructor).Append:552
        main.(*cmdRoot).Execute.func2:111
        main.(*cmdRoot).iterateRecords:211
        main.(*cmdRoot).Execute:110
        github.com/zeebo/clingy.(*Environment).dispatchDesc:129
        github.com/zeebo/clingy.Environment.Run:41
        main.main:30
        runtime.main:285

Are you using latest version of write-hashtbl? I remember a change to ignore collisions… :thinking:

I thought having the --fast flag was enough to ignore collisions. Thanks, I’ll try downloading the latest version.

@alpharabbit The latest version also crashes on collisions :cry:

root@PC3 ~/g/bin# ~/go/bin/write-hashtbl --fast  /mnt/Storj-5_18WB5/Storj_15/storage/hashstore/12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S/s1
...
Processing /mnt/Storj-5_18WB5/Storj_15/storage/hashstore/12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S/s1/ff/log-00000000000019ff-00000000...
Processing /mnt/Storj-5_18WB5/Storj_15/storage/hashstore/12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S/s1/ff/log-0000000000001aff-00000000...
hashstore: put:{key:14b80c184331bb7bdfeb7f87773fc7c04b465eab2ab2b5d3ff3150969cab36f5 offset:1068279680 log:5376 length:5632 created:20163 (2025-03-16) expires:0 (1970-01-01) trash:false} != exist:{key:14b80c184331bb7bdfeb7f87773fc7c04b465eab2ab2b5d3ff3150969cab36f5 offse>
        storj.io/storj/storagenode/hashstore.(*HashTbl).insertLocked:411
        storj.io/storj/storagenode/hashstore.(*HashTblConstructor).Append:552
        main.(*cmdRoot).Execute.func2:111
        main.(*cmdRoot).iterateRecords:211
        main.(*cmdRoot).Execute:110
        github.com/zeebo/clingy.(*Environment).dispatchDesc:129
        github.com/zeebo/clingy.Environment.Run:41
        main.main:30
        runtime.main:285

Please try the version from main:

go install storj.io/storj/cmd/write-hashtbl@main
Counting /storj/STORAGE/config/storage/hashstore/12L9ZFwhzVpuEKMUNUqkaTLGzwY9G24tbiigLiXpmZWKwmcNDDs/s1/ff/log-00000000000004ff-00000000...
Record count=1192471
Using logSlots=22
open hashtbl: file exists
        main.(*cmdRoot).Execute:97
        github.com/zeebo/clingy.(*Environment).dispatchDesc:129
        github.com/zeebo/clingy.Environment.Run:41
        main.main:30
        runtime.main:290

You need to remove the previously generated hashtbl before proceed.
It’s created in the current workdir.

ok, i’ve removed old hashtable file. now version from ‘main’ gives same result as ‘latest’:

Processing /storj/STORAGE/config/storage/hashstore/12L9ZFwhzVpuEKMUNUqkaTLGzwY9G24tbiigLiXpmZWKwmcNDDs/s1/ff/log-00000000000004ff-00000000...
hashstore: put:{key:368697015cb3eb710f70ad81855d6b6f5f948daad263bdba0a23ee333538b22e offset:972229120 log:1544 length:26368 created:20097 (2025-01-09) expires:0 (1970-01-01) trash:false} != exist:{key:368697015cb3eb710f70ad81855d6b6f5f948daad263bdba0a23ee333538b22e offset:629982208 log:1281 length:26368 created:20097 (2025-01-09) expires:0 (1970-01-01) trash:false}: hashstore: collision detected
        storj.io/storj/storagenode/hashstore.(*HashTbl).insertLocked:411
        storj.io/storj/storagenode/hashstore.(*HashTblConstructor).Append:563
        main.(*cmdRoot).Execute.func2:111
        main.(*cmdRoot).iterateRecords:211
        main.(*cmdRoot).Execute:110
        github.com/zeebo/clingy.(*Environment).dispatchDesc:129
        github.com/zeebo/clingy.Environment.Run:41
        main.main:30
        runtime.main:290

write-hashtbl appears to have a bug in how it handles hashstore.ErrCollision.

The intent in cmd/write-hashtbl/main.go is clearly to ignore collisions during reconstruction:

ok, err := tcons.Append(ctx, rec)
if errors.Is(err, hashstore.ErrCollision) {
    // ignore collisions ...
}

However, HashTblConstructor.Append() makes errors sticky internally:

So the actual behavior is:

  1. the first collision is observed in Append();
  2. main.go tries to ignore it;
  3. but Append() has already stored that collision in c.err;
  4. all subsequent appends are effectively poisoned;
  5. Done() fails at the end with the same collision.

This means collisions are not really ignored in practice, despite the comment in write-hashtbl.

One more detail: the final printed stack trace points to the first collision site, not the final Done() call, because errs preserves the stack from when the error was originally created. That makes the failure look like an immediate append failure even when the process only aborts at the end.

In short: cmd/write-hashtbl currently cannot successfully complete when duplicate records produce ErrCollision, even though the code comments explicitly say those collisions should be ignored.

Solutions

Option A: narrow fix, only for write-hashtbl

Change only cmd/write-hashtbl:

  • keep hashstore library untouched;
  • create the table with CreateTable(...);
  • immediately call Done() to obtain a Tbl;
  • insert reconstructed records with Tbl.Insert(...) instead of TblConstructor.Append(...).

Why this works:

  • TblConstructor.Append() has sticky error state;
  • Tbl.Insert() does not;
  • so write-hashtbl can continue to ignore ErrCollision locally, without changing global hashstore behavior.

Pros:

  • smallest blast radius;
  • no behavior change for other hashstore users;
  • safest choice if the bug is considered specific to this utility.

Cons:

  • changes the control flow of the utility more noticeably;
  • works around the constructor behavior instead of fixing it at the source.

Option B: broader fix in hashstore constructors

Change HashTblConstructor.Append() and MemTblConstructor.Append() so that ErrCollision is returned but not stored as sticky c.err.

Why this works:

  • callers like write-hashtbl can catch ErrCollision and continue;
  • Done() no longer fails later because of a previously ignored collision.

Pros:

  • smaller conceptual fix;
  • matches the expectation of callers that want to handle collisions explicitly;
  • preserves the existing CreateTable -> Append -> Done flow.

Cons:

  • affects all users of TblConstructor.Append(), not just write-hashtbl;
  • changes general hashstore semantics;
  • could weaken collision handling in other code paths that currently rely on sticky failure.

Recommendation

If the goal is “fix only write-hashtbl with minimal risk”, I would recommend Option A.

If the maintainers think “a caller that explicitly handles ErrCollision should always be able to continue”, then Option B is cleaner, but it is a library-wide behavior change and should be reviewed as such.

https://review.dev.storj.tools/c/storj/storj/+/20205

The version from main crashes in the same way as latest.

It seems we should wait while commit from previous message will be merged.

ok, now it’s working without errors.
I’ve got file hashtbl on 256M.
in meta folder there are file hashtbl-00000000000004b3 on 44M.
Should i just rename hashtbl and replace hashtbl-00000000000004b3? Why different sizes?

You need to remove the old hashtbl and put here a new one. Hash will be added to its name automatically.
Make sure that you moving to the correct location, if you scanned s0, put it to s0, if s1, then to s1. Please note - each storage should be scanned separately, scanned s0 - moved the file there, scanned s1, moved to s1.
Or change the current dir right to the correct place, then the hashtbl file will be generated in the correct place. However, the old table should be removed anyway.