jdx/mise · warning · eyre::Report
remote task action manifest changed too frequently
Error message
remote task action manifest changed too frequently
What it means
put_remote_task_manifest uploads the merged manifest with an If-Match ETag precondition. On PreconditionFailed it re-fetches the remote manifest, merges, and retries — but the loop runs only 4 iterations (for _ in 0..4). If another writer updates the remote manifest on every attempt, the CAS loop gives up and bails.
Source
Thrown at crates/mise-cache-core/src/agent.rs:671
let _permit = self.remote_transfers.acquire().await?;
remote
.put_action_manifest(&selector, &bytes, expected_etag.as_deref())
.await?
};
match outcome {
ManifestPutOutcome::Stored => return Ok(manifest),
ManifestPutOutcome::PreconditionFailed => {
let Some((remote_manifest, etag)) = self.get_remote_task_manifest(task).await?
else {
expected_etag = None;
continue;
};
manifest = merge_task_manifests(task, Some(remote_manifest), manifest)?;
expected_etag = Some(etag);
}
}
}
bail!("remote task action manifest changed too frequently")
}
/// Return a snapshot of this session's cache activity.
pub fn stats(&self) -> AgentStats {
AgentStats {
session_duration_ns: 0,
lookups: self.stats.lookups.load(Ordering::Relaxed),
hits: self.stats.hits.load(Ordering::Relaxed),
stores: self.stats.stores.load(Ordering::Relaxed),
stored_bytes: self.stats.stored_bytes.load(Ordering::Relaxed),
verifications: self.stats.verifications.load(Ordering::Relaxed),
divergences: self.stats.divergences.load(Ordering::Relaxed),
downloaded_bytes: self.stats.downloaded_bytes.load(Ordering::Relaxed),
uploaded_bytes: self.stats.uploaded_bytes.load(Ordering::Relaxed),
prefetched_actions: self.stats.prefetched_actions.load(Ordering::Relaxed),
remote_manifest_lookups: self.stats.remote_manifest_lookups.load(Ordering::Relaxed),
remote_manifest_lookup_duration_ns: self
.statsView on GitHub (pinned to 6f52dcdf99)
Solutions
- Retry the whole commit after a short backoff — begin_task/commit again; contention is usually transient
- Stagger concurrent task completions for the same task identity (queue or jitter the writers)
- If it persists, identify the client continuously rewriting that manifest entry (buggy writer) and stop it
Defensive patterns
Strategy: retry
Try / catch
let mut backoff = Duration::from_millis(500);
loop {
match agent.commit_task(&run).await {
Ok(_) => break,
Err(e) if e.to_string().contains("changed too frequently") && attempt < 3 => {
tokio::time::sleep(backoff).await;
backoff *= 2;
run = agent.begin_task(&task).await?; // fresh baseline + etag
}
Err(e) => return Err(e),
}
} Prevention
- Stagger concurrent commiters for the same task identity (jitter or queue writers)
- Treat this error as transient contention, not corruption — do not delete the remote entry for it
- Monitor commit retry rates to detect a pathological writer
When it happens
Trigger: Four or more concurrent sessions committing manifests for the same 64-hex task identity, each invalidating the others' ETags between get and put; a writer stuck in a rapid update loop on the same manifest key.
Common situations: A CI fleet fanning out many jobs for the same task finishing simultaneously against one shared remote cache; a misbehaving client rewriting the manifest entry in a tight loop.
Related errors
- task action manifest baseline was not loaded
- task action manifest is not canonical JSON
- remote rustc action metadata is invalid
- remote action output directory is invalid
- remote action descriptor is missing
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/a0a04257de39cd26.
Report an issue: GitHub.