linera-io/linera-protocol · error
Failed to save claims to database: {e}
Error message
Failed to save claims to database: {e} What it means
The faucet successfully committed the block that created chains / granted tokens on-chain, but then failed to persist the records to its own database: futures::try_join!(store_chains_batch, store_daily_claims_batch) errored. On-chain state and the faucet's DB are now out of sync — chains exist but are not recorded, which breaks the faucet's rate limiting and idempotency bookkeeping. The error message is sent to all waiting requesters and the batch processing aborts.
Source
Thrown at linera-faucet/server/src/lib.rs:1083
return Ok(());
}
self.faucet_storage
.store_chains_batch(initial_chains, block_timestamp)
.await
};
let store_daily = async {
if daily_claims.is_empty() {
return Ok(());
}
self.faucet_storage
.store_daily_claims_batch(daily_claims)
.await
};
if let Err(e) = futures::try_join!(store_initial, store_daily) {
let error_msg = format!("Failed to save claims to database: {e}");
Self::send_err(requests, error_msg.clone());
anyhow::bail!(error_msg);
}
// Respond to requests.
#[cfg(with_metrics)]
let chains_created = initial_desc_map.len();
for request in requests {
#[cfg(with_metrics)]
{
let wait_time = request.queued_at.elapsed().as_secs_f64() * 1000.0;
metrics::QUEUE_WAIT_TIME
.with_label_values(&[])
.observe(wait_time);
}
let response = if let Some(target_chain_id) = request.target_chain_id {
PendingResponse::Daily(Ok(ClaimOutcome {
chain_id: target_chain_id,View on GitHub (pinned to 6c226ddcb3)
Solutions
- Check the {e} inner error in faucet logs — it is the storage backend's message (table missing, auth, throttling).
- Restore DB connectivity/capacity (start local Dynamo, fix credentials/tables, raise write capacity).
- Reconcile: users whose chains were created but not recorded — they will be told the claim failed, and may need the record inserted manually or the daily-limit reset, otherwise re-claiming an existing chain can misbehave.
- Restart the faucet; queued requests re-attempt since failed responses were already sent.
Example fix
// before
if let Err(e) = futures::try_join!(store_initial, store_daily) {
let error_msg = format!("Failed to save claims to database: {e}");
Self::send_err(requests, error_msg.clone());
anyhow::bail!(error_msg);
}
// after: retry transient storage failures before giving up (on-chain state already committed)
let mut attempt = 0;
loop {
let r = futures::try_join!(store_initial(), store_daily());
match r {
Ok(()) => break,
Err(e) if attempt < 3 => { attempt += 1; tokio::time::sleep(Duration::from_secs(2_u64.pow(attempt))).await; }
Err(e) => { let m = format!("Failed to save claims to database: {e}"); Self::send_err(requests, m.clone()); anyhow::bail!(m); }
}
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight storage health before accepting claims: self.faucet_storage.store_daily_claims_batch(vec![]).await?; // or an explicit ping/health call
Try / catch
// On 'Failed to save claims to database': retry with backoff (transient DB outage); // after max attempts, reconcile manually — on-chain chains exist but the DB lacks records, // so re-processing the same requests must be idempotent (key by owner/period).
Prevention
- Provision/verify DB tables and capacity before opening the faucet (migration step in deployment).
- Alert on storage errors so drift is caught before users re-claim created chains.
- Make claim storage idempotent (upsert by owner + daily period) so retries after partial failure are safe.
When it happens
Trigger: process_batch commits the certificate, then store_chains_batch or store_daily_claims_batch hits a storage failure: DynamoDB/table not created, connection dropped, permission denied, write-capacity exceeded, or schema mismatch after a faucet version change.
Common situations: AWS DynamoDB (or configured store) credentials/tables missing or misconfigured; DB briefly unavailable during a batch; faucet upgraded without running the storage migration; local Dynamo not started in dev.
Related errors
- Returned AccountInfo should have code: Some(...) and so code
- Returned AccountInfo should have code: Some(...) and so code
- no errors present but no data returned
- owner should be different from spender
- invalid block export configuration: {message}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/56a2a2348a099db9.
Report an issue: GitHub.