Publication
Partagez vos connaissances.
+15
Échec de la transaction Sui : objets réservés pour une autre transaction
Je rencontre un problème persistant JsonRpcError
lorsque j'essaie d'exécuter des transactions sur Sui. L'erreur indique que les objets sont réservés pour une autre transaction, même si j'ai implémenté un traitement séquentiel des transactions avec des retards.
JsonRpcError: Failed to sign transaction by a quorum of validators because one or more of its objects is reserved for another transaction. Other transactions locking these objects:
- AV7coSQHWg5vN3S47xada6UiZGW54xxUNhRv1QUPqWK (stake 33.83)
- 0x1c20f15cbe780ee7586a2df90c1ab70861ca77a15970bea8702a8cf97bd3eed9
- 0x1c20f15cbe780ee7586a2df90c1ab70861ca77a15970bea8702a8cf97bd3eed9
- 0x1c20f15cbe780ee7586a2df90c1ab70861ca77a15970bea8702a8cf97bd3eed9
J'ai essayé :
- Exécution séquentielle des transactions (en attente de la fin de la transaction précédente)
- Ajout de délais de 3 secondes entre les transactions
Et j'obtiens toujours la même erreur.
Utilisation de Sui RPC pour la soumission des transactions. Le même identifiant d'objet apparaît plusieurs fois dans la liste de verrouillage. Une erreur se produit même avec un séquençage minutieux des transactions.
- Qu'est-ce qui fait que les objets sont « réservés » pour d'autres transactions ?
- Comment puis-je vérifier correctement si un objet est disponible avant de l'utiliser dans une transaction ?
- Existe-t-il des bonnes pratiques pour gérer les verrous d'objets dans Sui ?
- Cela pourrait-il être lié au calendrier de finalité de la transaction ?
Quelqu'un a-t-il déjà rencontré ce problème ? Toute information sur la gestion appropriée des objets dans les transactions Sui serait grandement appréciée !
- Sui
- Transaction Processing
- Move
Réponses
10Cette erreur se produit si vous essayez d'exécuter deux transactions simultanément (par exemple, en démarrer une avant la fin de la précédente). Si vous réessayez d'exécuter la transaction de publication, sans exécuter une autre transaction avant ou en même temps, elle devrait réussir. Vous devrez peut-être aussi vous procurer plus d'essence au robinet (ou attendre un jour, le temps que l'époque change, pour que les objets soient déverrouillés)
Lorsque vous exécutez une transaction impliquant des objets appartenant à votre adresse (comme les objets à gaz), les validateurs réservent la dernière version de l'objet à utiliser pour la transaction qu'il signe. Si vous essayez d'exécuter deux transactions simultanément et qu'elles font référence au même objet, elles se feront concurrence pour les signatures des validateurs. Dans le cas heureux, l'une des transactions gagne et s'exécute, tandis que l'autre ne parvient pas à obtenir suffisamment de signatures. Dans le cas malheureux, les deux transactions peuvent ne pas obtenir suffisamment de signatures (si les deux ont obtenu plus d'un tiers des signatures du validateur, aucune ne peut obtenir plus des deux tiers, ce qui est le seuil), c'est ce qu'on appelle une équivoque, et à partir de ce moment, les objets qui ont été entrés dans les deux transactions ne peuvent plus être utilisés pour aucune autre transaction.
À la fin de l'époque (ils durent environ une journée — vous pouvez vérifier la progression jusqu'au prochain changement d'époque sur https://suiexplorer.com), tous les verrous sont libérés, vous pouvez donc réutiliser les objets, mais si vous n'avez pas changé d'époque depuis votre dernière tentative, vous devrez vous procurer plus de gaz.
Hé, vous essayez de faire une transaction trop rapidement et les objets ont été verrouillés.
Essayez d'envoyer une transaction avec les mêmes objets à la fois. Si vous envoyez deux transactions, certains validateurs peuvent accepter la première, d'autres pourraient accepter la seconde et vos objets seront bloqués car chaque transaction nécessite 66,7 % de validateurs et vous n'en obtenez peut-être que 50 %.
=> attendez que l'époque soit réinitialisée, c'est bientôt
Pour en savoir plus : https://forums.sui.io/t/beginner-tutorial-error-when-deploying-simple-sui-package/44842
Sui utilise uncontrôle de simultanéité optimiste, ce qui signifie que les objets sont verrouillés lorsqu'ils sont utilisés dans une transaction jusqu'à ce que cette transaction soit finalisée ou expire.
Même si vous attendez 3 secondes entre les transactions, si la précédente n'a pas été finalisée, l'objet reste verrouillé. Cela signifie que la transaction est toujours en attente et qu'elle détient un accès exclusif à l'objet.
Comment vérifier si un objet est disponible
Utilisez la méthode Sui RPC :
sui_getObject
Vérifiez la réponse pour "status": "Locked"
ou"owner": "locked"
.
Exemple de demande :
{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getObject",
"params": ["0x...object_id..."]
}
S'il est verrouillé, attendez plus longtemps et réessayez plus tard.
L'erreur signifie que les objets utilisés par votre transaction sont toujours bloqués par des transactions précédentes qui n'ont pas encore été finalisées. Malgré les retards, les objets restent réservés jusqu'à ce que ces transactions soient effectuées en chaîne.
Pour corriger :
- Vérifiez toujours que les transactions précédentes impliquant les objets ont été entièrement finalisées avant de les réutiliser.
- Vérifiez l'état des objets via Sui RPC pour vous assurer qu'ils sont déverrouillés.
- Évitez d'envoyer des transactions parallèles ou rapides sur les mêmes objets.
- Mettez en œuvre de nouvelles tentatives avec des contrôles d'annulation et de finalité au lieu de délais fixes.
Ce verrouillage empêche les mises à jour contradictoires et est normal dans le modèle d'objet de Sui. JsonRpcError
Un séquençage et une confirmation de finalité appropriés sont essentiels pour éviter.
Cette erreur signifie que les objets que vous utilisez sont toujours bloqués par des transactions antérieures qui n'ont pas encore été finalisées. Même en cas de retard, Sui les réserve jusqu'à ce que la chaîne confirme l'achèvement.
Pour résoudre ce problème, assurez-vous que toutes les transactions précédentes utilisant ces objets sont entièrement finalisées avant de les réutiliser. Vous pouvez vérifier leur statut via Sui RPC pour voir s'ils sont déverrouillés. Évitez d'envoyer des transactions multiples ou rapides impliquant les mêmes objets. Au lieu de vous fier à des délais fixes, utilisez les nouvelles tentatives avec annulation et confirmez le caractère définitif avant de réessayer.
Ce verrouillage fait partie de la façon dont Sui garantit la sécurité des mises à jour. Un séquençage et une finalité de vérification appropriés sont donc le moyen d'éviter JSONRPCEerror
That’s a great debugging question — I’ve run into this exact issue before when building staking flows on Sui. Let me answer in detail, step-by-step, from my perspective using Sui daily.
🔍 Why objects get “reserved” in Sui
In Sui, every transaction consumes specific object versions. Once you submit a transaction that references an object, the network puts a lock on that object version until the transaction is finalized (committed or fails).
So when you see:
JsonRpcError: Failed to sign transaction ... one or more of its objects is reserved
it means:
- The object version you’re trying to use is still “in flight” (reserved by another PTB),
- Or you’re re-using an outdated version without refreshing from the fullnode,
- Or the validator quorum hasn’t yet reached finality for the first transaction.
That’s why the same objectId
shows multiple times in the lock list — you’re trying to consume the same locked version repeatedly.
✅ How I check object availability before using
I always follow these steps:
-
After each transaction, re-fetch fresh object refs before building the next transaction block.
const fresh = await provider.getObject({ id: "0x1c20f15cbe780ee...", options: { showOwner: true, showPreviousTransaction: true, showContent: true }, }); const version = fresh.data.version; // must use this version in the next PTB
-
Wait for local execution / finality when submitting. Always request
WaitForLocalExecution
in yoursignAndExecuteTransactionBlock
. This ensures the object is unlocked before you try to use it again.const res = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx, requestType: "WaitForLocalExecution", });
-
Implement a retry with exponential backoff when conflicts occur. Even with sequencing, there are cases where the fullnode lags. I use a
submitWithRetry
wrapper (like the one I showed earlier) that catchesObject version mismatch
and retries after re-fetching the object.
⚡ Best practices for handling object locks
- Never reuse old object references. Always fetch the latest state from the RPC before constructing each PTB.
- Design with parallelism in mind. If multiple independent flows need the same object, shard state across multiple owned objects (avoid a single global shared object).
- Batch operations when possible. Use a single
TransactionBlock
with multiple Move calls instead of sending sequential transactions that lock the same object repeatedly. - Add backoff + retries. I usually back off
100ms, 200ms, 400ms, 800ms … up to ~3s
before giving up. - Use checkpoints/finality awareness. Remember: an object isn’t truly free until the checkpoint is committed.
⏱️ Relation to finality timing
Yes, this is directly related. Even after a transaction appears “executed”, the object may remain reserved until:
- The local fullnode confirms execution,
- The consensus checkpoint includes it,
- The version updates propagate across validators.
That’s why adding a blind 3-second delay
isn’t reliable — network conditions and validator lag can extend this. The right way is fetch-after-execution instead of sleeping.
🛠️ Example: Safe sequential staking
Here’s how I do it in code (simplified):
async function safeStake(signer, validatorAddr, stakeAmountMist, stakeObjectId) {
let attempt = 0;
while (attempt < 5) {
try {
// 1. Fetch latest object version
const obj = await provider.getObject({ id: stakeObjectId, options: { showOwner: true } });
const version = obj.data.version;
// 2. Build PTB with fresh version
const tx = new TransactionBlock();
tx.moveCall({
target: "0x2::staking::request_add_stake",
arguments: [tx.pure(validatorAddr), tx.pure(stakeAmountMist.toString())],
typeArguments: [],
});
// 3. Execute with finality wait
const res = await signer.signAndExecuteTransactionBlock({
transactionBlock: tx,
requestType: "WaitForLocalExecution",
});
console.log("✅ success:", res.digest);
return res;
} catch (e) {
if (e.message.includes("reserved") || e.message.includes("Object version mismatch")) {
attempt++;
const backoff = 200 * 2 ** attempt;
console.warn(`conflict, retrying in ${backoff}ms`);
await new Promise(r => setTimeout(r, backoff));
continue;
}
throw e;
}
}
throw new Error("failed after retries");
}
This ensures:
- I always use the latest object version,
- I wait for finality,
- I retry on transient lock errors.
🧩 TL;DR
- Cause: Object locks happen because an object version is still reserved by an in-flight transaction.
- Fix: Always re-fetch latest object versions, wait for local execution, and retry on conflicts.
- Best practice: Shard state, batch operations, and use retries/backoff rather than fixed sleeps.
- Yes, finality timing matters. Blind delays won’t solve it — confirmation checks + re-fetching will.
Connaissez-vous la réponse ?
Veuillez vous connecter et la partager.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Gagne ta part de 1000 Sui
Gagne des points de réputation et obtiens des récompenses pour avoir aidé la communauté Sui à se développer.
- Comment maximiser la détention de profits SUI : Sui Staking contre Liquid Staking615
- Pourquoi BCS exige-t-il un ordre de champs exact pour la désérialisation alors que les structures Move ont des champs nommés ?65
- « Erreurs de vérification de sources multiples » dans les publications du module Sui Move - Résolution automatique des erreurs55
- Erreur Sui Move - Impossible de traiter la transaction Aucune pièce de gaz valide n'a été trouvée pour la transaction419
- Échec de la transaction Sui : objets réservés pour une autre transaction410