--- a/sys/vfs/hammer2/hammer2_synchro.c 2026-10-15 07:16:23.700535111 +0000 +++ b/sys/vfs/hammer2/hammer2_synchro.c 2026-10-15 07:16:39.628330073 +0000 @@ -755,7 +755,23 @@ &error, HAMMER2_LOOKUP_NODIRECT | HAMMER2_LOOKUP_ALWAYS); - KKASSERT(chain == NULL); + if (chain) { + /* + * TOCTOU: the scan ran with the inode unlocked and the + * parent shared, so a concurrent VOP create/rename on the + * mounted rw cluster can have inserted the same key on + * our column between the scan and this exclusive + * re-lookup. The racing creator wrote the key to ALL + * columns in one cluster transaction, so dropping our + * stale insert keeps the columns consistent; retry via + * EAGAIN. + */ + hammer2_chain_unlock(chain); + hammer2_chain_drop(chain); + chain = NULL; + error = HAMMER2_ERROR_EAGAIN; + goto failed; + } chain = NULL; error = hammer2_chain_create(parentp, &chain, NULL, thr->pmp,