Skip to content
LogoLogo

Known limitations

What this release does not handle yet, and what to do instead

These are the limits we know of in this release. Each one names what happens, whether money is at risk, and what to do until it is fixed. Most are fixed in the next beta; the first one needs a change outside nautilus.

LimitationMoney at risk?Workaround
The credential type alone is not a reliable gateNo, but data can reach the wrong consumerGate on trusted issuers and an explicit address allow list
One download URL at a time per consumer and nodeNoUse each URL before you request the next
Buying the same service in parallel from one keyNo, gas onlyDon't buy the same service concurrently from one key
A second access() right after buying can buy againYes, one extra purchaseWait until at least 2 more blocks are mined after the purchase; use a reliable RPC
Every compute() buys its paid inputs againYes, one purchase per input per jobPrice compute services as free, or expect one purchase per job
Orders older than about 55 hours are not foundYes, with the opt-inPaid services with a timeout of at most 24 hours (48 on an RPC serving 1,000+ blocks per eth_getLogs); opt in only for a first purchase
A stuck fee approval gives an unclear errorNoNone needed
getAssets returns nothing on ocean-node 4.2NoUse getAsset(did) per asset
Revoking after deprecatingNoRevoke directly, or keep the asset object from before deprecating

The credential type alone is not a reliable gate

The credential check of a gated asset runs in the node's policy server and the walt.id verifier, not in nautilus. In this release, the type of a presented credential alone is not a reliable gate: a consumer can get past a check that relies on the type without holding a credential from an issuer you trust.

Workaround: enforce trust with the issuer check and an explicit address allow list, and use both on every gated asset. Gate on a specific credential type with trusted issuers, and always list the allowed addresses: the consumer signs the download with their Ethereum key, and the policy server checks that address whatever credential was presented. Never combine a credential gate with '*' in the allow list: that leaves no gate at all. See credential-gated assets.

Fixed by: the policy server or walt.id (outside nautilus).

One download URL at a time per consumer and node

access() returns a download URL signed with a one-time number (a nonce) that the node checks when you fetch it. The node accepts a number only if it is higher than the last one it accepted from you. A URL is signed with "the last accepted number plus one", and the node counts a number as used only when a URL is fetched. So two URLs requested for the same consumer and node before either is fetched carry the same number: the first one fetched works, and the other is refused with HTTP 401:

HTTP 401: nonce: 110 is not a valid nonce

That URL was replaced by a newer one for the same consumer and node. nautilus does not fetch the URL itself, so it cannot turn this answer into a clearer error for you.

Workaround: use each URL before you request the next one, and don't call access() for the same consumer and node in parallel. If a download answers 401 with is not a valid nonce, call access() again and fetch the new URL right away. access() looks for the order you already hold and reuses it when it finds one (reusedOrder says so). For a paid service, first wait until at least 2 more blocks are mined after the purchase: an access() sooner than that does not find the order and pays again (see a second access() right after buying).

Fixed by: the next beta (nautilus will issue the numbers itself).

Buying the same service in parallel from one key

Three access() calls for the same paid service from the same key at the same time: one order goes through, and the other two transactions fail (reverted on chain) with a generic error. Nothing is paid twice, but the gas of the failed transactions is lost.

Workaround: don't buy the same service concurrently from one key. Call access() once and wait for it. For a paid service, wait until at least 2 more blocks are mined after the purchase before you call it again: then it finds the order and reuses it. Sooner, it buys again (see a second access() right after buying).

Fixed by: the next beta (concurrent calls for the same service share one purchase).

A second access() right after buying can buy again

Before buying, access() looks for an order you already hold. It reuses an order only once at least 2 more blocks are mined on top of the block that holds it, since a reorg could still drop a newer one (see the order on chain). access() returns as soon as its own order is mined, so a second access() for the same paid service started before those 2 blocks does not find that order, and pays again. An RPC whose view of the chain lags behind (a load balancer whose backends are not in sync, for example) extends that wait by as many blocks as it lags.

How long 2 blocks take depends on the chain: on OP Sepolia, with a block about every 2 seconds, a few seconds. A local development chain that mines a block only when a transaction arrives does not advance by waiting at all.

Workaround: after buying a paid service, wait until at least 2 more blocks are mined before you access it again (compare the block number of the purchase with the chain's latest block; allow more if your RPC lags). Use a reliable RPC, and set verificationProvider for paid flows.

Fixed by: the next beta (an order this process just placed is remembered, and a very new order is never bought again).

Every compute() buys its paid inputs again

Each compute() call orders, and pays for, every paid dataset and every paid algorithm of the job again, even while an order you placed for an earlier job is still valid. Unlike access(), compute() does not look for an order you already hold, and the node does not report one either. Two jobs on the same paid dataset pay for it twice.

Workaround: price the compute services of your datasets and algorithms as free, or expect one purchase per paid input on every job and budget for it.

Fixed by: a later release (compute() reuses an order you already hold, as access() does).

Orders older than about 55 hours are not found

The order check reads back only the last 100,000 blocks, about 55 hours on OP Sepolia. For a paid service whose orders last longer (timeout: 0, which means they never expire, or a timeout of more than about 55 hours), the check cannot see all of the time an order stays valid. When it finds no order of yours in those 55 hours, access() stops with an OrderCheckError whose reason is incomplete, and pays nothing. That happens on the first purchase, and again once your order is older than about 55 hours. Passing orderOnLookupFailure: true then buys; for an older order that is still valid, that pays a second time. Within about 55 hours of a purchase (less on an RPC that serves 100 blocks per eth_getLogs call, about 40 hours), the order is found and reused.

Workaround: publish paid services with a timeout the check can read within its 5 minutes, and use the opt-in only for a first purchase, when you know the account holds no order for the service. How long a timeout that allows depends on the RPC: the check needs an RPC that answers eth_getLogs for at least 100 blocks per call, and reads the whole timeout before it pays. On an RPC that serves only 100 blocks per call (about 0.4 s per call), a 24-hour service takes about 450 reads, about 3 minutes, and a 48-hour service does not fit in the 5 minutes. So keep paid services at 24 hours or less on such an RPC. An RPC that serves 1,000 blocks or more per call reads the whole 100,000-block depth, about 55 hours; keep paid services at 48 hours or less there. When the reads end before they cover the timeout, access() stops with an incomplete OrderCheckError that asks for another RPC, and nothing is paid.

Fixed by: the next beta (a deeper read, and for timeout: 0 a read from the datatoken's creation).

A stuck fee approval gives an unclear error

When nautilus approves a provider fee's token and that approval is sent but never confirms (dropped or stuck in the mempool), a later failure on the same token gets a generic error instead of one that names the stuck approval. Nothing is paid twice.

Workaround: none needed. If a payment stops with an unclear error, look up the account's pending transactions in a block explorer and retry once they are mined or dropped.

Fixed by: the next beta.

getAssets returns nothing on ocean-node 4.2

getAssets() returns {} against ocean-node 4.2.x, even for assets that exist: the node answers the query in a shape nautilus does not read yet.

Workaround: call getAsset(did) for each asset.

Fixed by: the next beta.

Revoking after deprecating

Once an asset is DEPRECATED, ocean-node 4.2 with Elasticsearch drops its document, so getAsset answers 404 and there is no asset object left to pass to setAssetLifecycleState. Revoking it through nautilus then fails.

Workaround: to withdraw an asset, set REVOKED_BY_PUBLISHER directly instead of deprecating it first. If you deprecate, keep the asset object you read before (getAsset, or the ddo of publish()): it holds the NFT address the transaction needs, and setAssetLifecycleState can still revoke with it.

Fixed by: the next beta (lifecycle changes by NFT address).