Publicación
Comparte tu conocimiento.
+15
Fallo en la transacción Sui: objetos reservados para otra transacción
Me encuentro con un problema persistente JsonRpcError
al intentar ejecutar transacciones en Sui. El error indica que los objetos están reservados para otra transacción, aunque he implementado el procesamiento secuencial de las transacciones con retrasos.
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
He intentado:
- Ejecución secuencial de la transacción (esperando a que se complete la transacción anterior)
- Se agregaron retrasos de 3 segundos entre transacciones
Y sigo recibiendo el mismo error de forma constante.
Uso de Sui RPC para el envío de transacciones. El mismo ID de objeto aparece varias veces en la lista de objetos bloqueados. El error se produce incluso con una secuenciación cuidadosa de las transacciones.
- ¿Qué hace que los objetos se «reserven» para otras transacciones?
- ¿Cómo puedo comprobar correctamente si un objeto está disponible antes de usarlo en una transacción?
- ¿Existen mejores prácticas para gestionar los bloqueos de objetos en Sui?
- ¿Podría estar relacionado con el tiempo de finalización de la transacción?
¿Alguien se ha encontrado con este problema antes? ¡Cualquier información sobre la gestión adecuada de objetos en las transacciones de Sui sería muy apreciada!
- Sui
- Transaction Processing
- Move
Respuestas
10Este error se produce si intenta ejecutar dos transacciones simultáneamente (por ejemplo, iniciar una antes de que finalice la anterior). Si vuelves a intentar ejecutar la transacción de publicación sin ejecutar otra transacción antes o al mismo tiempo, debería realizarse correctamente. También es posible que tengas que sacar más gasolina del grifo (o esperar un día, a que pase la época, a que los objetos se desbloqueen)
Cuando realizas una transacción en la que intervienen objetos de tu dirección (como los objetos de gas), los validadores reservan la última versión del objeto para que la utilice la transacción que está firmando. Si intentas ejecutar dos transacciones simultáneamente y se refieren al mismo objeto, competirán entre sí por las firmas de los validadores. En este caso, una de las transacciones gana y se ejecuta, y la otra no consigue suficientes firmas. En el caso desafortunado, es posible que ambas transacciones no obtengan suficientes firmas (si ambas obtuvieron más de un tercio de las firmas del validador, ninguna de las dos podrá superar los dos tercios, que es el umbral), esto se denomina equívoco y, a partir de ese momento, los objetos que sirvieron de entrada a ambas transacciones no se pueden utilizar para ninguna otra transacción.
Al final de la época (duran aproximadamente un día; puedes comprobar el progreso hasta el siguiente cambio de época en https://suiexplorer.com), se liberan todos los bloqueos, por lo que puedes volver a utilizar los objetos, pero si no has cambiado de época desde la última vez que lo intentaste, necesitarás adquirir más gas.
Oye, estás intentando realizar una transacción demasiado rápido y los objetos se han bloqueado.
Intenta enviar una transacción con los mismos objetos a la vez. Si envías dos transacciones, es posible que algunos validadores acepten la primera, otros acepten la segunda y tus objetos se bloquearán porque cada transacción necesita un 66,7% de validadores y es posible que solo obtengas el 50%.
=> espera a que se restablezca la época, ¡es pronto
Consulta más información: https://forums.sui.io/t/beginner-tutorial-error-when-deploying-simple-sui-package/44842
Sui utiliza uncontrol de concurrencia optimista, lo que significa que los objetos se bloquean cuando se utilizan en una transacción hasta que la transacción finalice o caduque.
Aunque esperes 3 segundos entre una transacción y otra, si la anterior no se ha finalizado, el objeto permanece bloqueado. Esto significa que la transacción sigue pendiente y tiene acceso exclusivo al objeto.
Cómo comprobar si un objeto está disponible
Utilice el método Sui RPC:
sui_getObject
Compruebe la respuesta para "status": "Locked"
o"owner": "locked"
.
Ejemplo de solicitud:
{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getObject",
"params": ["0x...object_id..."]
}
Si está bloqueado, espera un poco más y vuelve a intentarlo más tarde.
El error significa que los objetos que usa tu transacción siguen bloqueados por transacciones anteriores que aún no se han finalizado. Incluso con retrasos, los objetos permanecen reservados hasta que esas transacciones se completen en cadena.
Para solucionarlo:
- Confirme siempre que las transacciones anteriores relacionadas con los objetos se hayan finalizado por completo antes de volver a utilizarlos.
- Comprueba el estado de los objetos a través de Sui RPC para asegurarte de que están desbloqueados.
- Evite enviar transacciones paralelas o rápidas sobre los mismos objetos.
- Implemente los reintentos con comprobaciones de finalización y retroceso en lugar de demoras fijas.
Este bloqueo evita actualizaciones conflictivas y es normal en el modelo de objetos de Sui. JsonRpcError
La secuenciación adecuada y la confirmación de la finalidad son fundamentales para evitarlo.
Este error significa que los objetos que estás utilizando siguen bloqueados por transacciones anteriores que aún no se han finalizado. Incluso con retrasos, Sui los mantiene reservados hasta que la cadena confirme su finalización.
Para solucionarlo, asegúrate de que todas las transacciones anteriores con esos objetos estén completamente finalizadas antes de volver a utilizarlas. Puedes comprobar su estado a través de Sui RPC para ver si están desbloqueados. Evita enviar transacciones múltiples o rápidas que involucren los mismos objetos. En lugar de confiar en demoras fijas, utiliza los reintentos con retraso y confirma la finalidad antes de volver a intentarlo.
Este bloqueo es parte de la forma en que Sui garantiza la seguridad de las actualizaciones, por lo que la secuenciación adecuada y la comprobación de la finalidad son la forma de evitar el error JsonRPCError
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.
Sabes la respuesta?
Inicie sesión y compártalo.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Gana tu parte de 1000 Sui
Gana puntos de reputación y obtén recompensas por ayudar a crecer a la comunidad de Sui.
- Cómo maximizar la retención de ganancias SUI: Sui Staking versus Liquid Staking615
- ¿Por qué BCS requiere un orden de campo exacto para la deserialización cuando las estructuras Move tienen campos con nombre?65
- «Errores de verificación de múltiples fuentes» en las publicaciones del módulo Sui Move: resolución automática de errores55
- Error de movimiento: no se puede procesar la transacción No se han encontrado monedas de gasolina válidas para la transacción419
- Fallo en la transacción Sui: objetos reservados para otra transacción410