block/buzz · error · anyhow::Error
project announcement timestamp is too far in the future
Error message
project announcement timestamp is too far in the future
What it means
A project announcement's created_at (taken from the template, defaulting to now) must not be more than 300 seconds in the future. This guard prevents far-future timestamps, which would defeat relay last-write-wins ordering and pin the announcement forever.
Source
Thrown at crates/buzz-acp/src/lib.rs:1734
anyhow::bail!("unsupported project announcement kind");
}
if !template.tags.iter().any(|tag| {
tag.first().is_some_and(|value| value == "d")
&& tag.get(1).is_some_and(|value| !value.trim().is_empty())
}) {
anyhow::bail!("project announcement is missing its address");
}
let tags = template
.tags
.into_iter()
.map(|tag| {
nostr::Tag::parse(tag)
.map_err(|error| anyhow::anyhow!("invalid project tag: {error}"))
})
.collect::<Result<Vec<_>>>()?;
let created_at = template.created_at.unwrap_or(now);
if created_at > now.saturating_add(300) {
anyhow::bail!("project announcement timestamp is too far in the future");
}
nostr::EventBuilder::new(nostr::Kind::Custom(template.kind), template.content)
.tags(tags)
.custom_created_at(nostr::Timestamp::from(created_at))
.sign_with_keys(keys)
.map_err(|error| anyhow::anyhow!("sign project announcement: {error}"))
})
.collect()
}
fn emit_project_owner_control_result(
observer: Option<&observer::ObserverHandle>,
request_id: &str,
status: &str,
events: &[nostr::Event],
error: Option<String>,
) {
let Some(observer) = observer else {View on GitHub (pinned to dad5a33865)
Solutions
- Remove created_at from the template so it defaults to the harness's current time
- Or set created_at to a value at or before the moment the harness starts
- Sync the machine that generates the config and the harness host with NTP
Example fix
# agent config
# before
project_owner_announcements:
- kind: 30621
tags: [["d", "my-project"]]
created_at: 4102444800
# after
project_owner_announcements:
- kind: 30621
tags: [["d", "my-project"]]
# created_at omitted -> defaults to now Defensive patterns
Strategy: validation
Validate before calling
// Preflight: reject templates whose created_at is more than 5 minutes ahead
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?.as_secs();
if let Some(ts) = template.created_at {
if ts > now + 300 { anyhow::bail!("created_at {ts} is more than 300s ahead of host clock {now}"); }
} Prevention
- Omit created_at in generated templates and let the harness stamp now
- Keep NTP enabled on machines that author or run agent configs; clock skew breaks all Nostr timestamp checks, not just this one
When it happens
Trigger: A template explicitly sets created_at more than now+300s, or the template's created_at was computed on a machine whose clock runs more than 5 minutes ahead of the harness host's clock.
Common situations: NTP drift on the workstation that authored the config; a CI pipeline with a skewed clock stamping generated templates; daylight-saving or timezone math bugs producing future timestamps.
Related errors
- unsupported project announcement kind
- project announcement is missing its address
- moderation notice recipient must be a 32-byte pubkey, got {}
- BUZZ_RELAY_PRIVATE_KEY must be set when BUZZ_REQUIRE_AUTH_TO
- malformed {SETUP_PAYLOAD_ENV_VAR}: {e}
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-20).
Data as JSON: /api/errors/256c3226d1e0b5d2.
Report an issue: GitHub.