linera-io/linera-protocol · warning · async_graphql::Error

You have already claimed tokens for this period

Error message

You have already claimed tokens for this period

What it means

Each owner may make one daily claim per 24-hour period, where period numbers are computed from the owner's initial claim timestamp (`(now - initial_claim) / 24h`, lib.rs:412-414). The faucet refuses with DAILY_LIMIT_MSG when the current period is <= the last claimed period. The window is anchored to your initial claim time (not midnight), and the initial claim itself counts as a claim in period 0.

Source

Thrown at linera-faucet/server/src/lib.rs:588

                .with_label_values(&["daily_no_chain"])
                .inc();
            return Err(Error::new(DAILY_NO_CHAIN_MSG));
        };

        let now = self.storage.clock().current_time();
        let period = current_daily_period(initial_claim.timestamp.micros(), now.micros());
        let last_period = self
            .faucet_storage
            .last_daily_claim_period(&owner)
            .await?
            .unwrap_or(0);

        if period <= last_period {
            #[cfg(with_metrics)]
            metrics::CLAIM_REQUESTS_TOTAL
                .with_label_values(&["daily_limit"])
                .inc();
            return Err(Error::new(DAILY_LIMIT_MSG));
        }

        self.enqueue_daily_request(
            owner,
            initial_claim.chain_id,
            destination,
            self.daily_claim_amount,
            period,
        )
        .await
    }

    async fn enqueue_daily_request(
        &self,
        owner: AccountOwner,
        target_chain_id: ChainId,
        destination: AccountOwner,
        amount: Amount,

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Wait until the next period and retry — query `nextDailyClaim(owner)` for the exact unlock timestamp (initial_claim + (last_period + 1) * 24h)
  2. Track the cooldown client-side: next allowed time = initial claim timestamp + (last claimed period + 1) * 24 hours
  3. Ensure only one in-flight `dailyClaim` per owner (single-flight) so retries don't race the front-door check
  4. In tests, advance the mock clock past 24h (DAILY_PERIOD_MICROS) between daily claims

Example fix

// before - fire dailyClaim on a fixed cron schedule
client.daily_claim(owner, None).await?;

// after - gate on the faucet's own cooldown clock
let next = client.next_daily_claim(owner).await?; // Option<Timestamp>
if let Some(unlock) = next {
    if unlock > now { /* schedule the claim at `unlock`, not at a fixed time */ }
}
client.daily_claim(owner, None).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Run before dailyClaim:
//   query { nextDailyClaim(owner: "<AccountOwner>") }
//     -> Some(timestamp): wait until it is in the past, then claim.
//     -> null: no initial claim exists yet (claim first).
// The cooldown is anchored at the owner's initial claim time, not midnight.

Type guard

fn is_daily_cooldown(msg: &str) -> bool { msg == "You have already claimed tokens for this period" }

Try / catch

Catch the `dailyClaim` error; on `You have already claimed tokens for this period`, query `nextDailyClaim(owner)` and reschedule the call for that timestamp. Never retry immediately — the refusal is deterministic until the next 24h period.

Prevention

When it happens

Trigger: A second `dailyClaim` within the same 24h window anchored at the initial claim; a concurrent duplicate that raced past the front-door check and is refused again during batch validation (lib.rs:856-858); automated jobs scheduled more than once a day.

Common situations: Cron bots running at fixed clock times that drift against the per-owner anchor; retries after client timeouts where the first attempt actually succeeded; test loops calling `dailyClaim` repeatedly without advancing the clock by 24h.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/aeb73b51ce47d7c7. Report an issue: GitHub.