block/buzz · error · IngestError::Rejected

invalid archived value: {v} (must be "true" or "false")

Error message

invalid archived value: {v} (must be "true" or "false")

What it means

Thrown when a kind:9002 event carries an "archived" tag whose value is neither the exact string "true" nor "false". Values are compared case-sensitively as strings before storage, so boolean JSON true, "TRUE", "1", or "yes" are all rejected.

Source

Thrown at crates/buzz-relay/src/handlers/side_effects.rs:519

                "ttl",
            ];
            let has_recognized = event
                .tags
                .iter()
                .any(|t| RECOGNIZED_TAGS.contains(&t.kind().to_string().as_str()));
            if !has_recognized {
                return Err(anyhow::anyhow!(
                    "kind:9002 must include at least one metadata tag (name, about, archived, topic, purpose, visibility, ttl)"
                ));
            }

            // Validate archived values before storage.
            for t in event.tags.iter() {
                if t.kind().to_string() == "archived" {
                    match t.content() {
                        Some("true") | Some("false") => {}
                        Some(v) => {
                            return Err(anyhow::anyhow!(
                                "invalid archived value: {v} (must be \"true\" or \"false\")"
                            ));
                        }
                        None => {
                            return Err(anyhow::anyhow!("archived tag must have a value"));
                        }
                    }
                }
            }

            // Validate channel names before storage. A name made entirely of
            // display-prefix hashes becomes empty after canonicalization.
            for t in event.tags.iter() {
                if t.kind().to_string() == "name" {
                    match t.content() {
                        Some(v)
                            if !buzz_core::channel::canonical_channel_name(v)
                                .trim()

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Send the lowercase string "true" or "false" as the tag value: ["archived", "false"].
  2. If your data model stores booleans, convert explicitly at serialization: value ? "true" : "false".
  3. Lint event payloads for archived tag values matching /^(true|false)$/ before publish.

Example fix

// before
{ kind: 9002, tags: [["h", ch], ["archived", isArchived ? 1 : 0]] }

// after
{ kind: 9002, tags: [["h", ch], ["archived", isArchived ? "true" : "false"]] }
Defensive patterns

Strategy: type-guard

Validate before calling

// Normalize booleans to the exact relay enum before publish
function archivedTag(value: boolean): string[] {
  return ["archived", value ? "true" : "false"];
}

Type guard

function isValidArchivedValue(v: string): boolean {
  return v === "true" || v === "false";
}

// fail fast before publishing
for (const t of tags.filter((t) => t[0] === "archived")) {
  if (!isValidArchivedValue(t[1] ?? "")) throw new Error(`archived must be "true" or "false", got ${t[1]}`);
}

Try / catch

try {
  await sdk.publish(editEvent);
} catch (e) {
  if (String(e).includes("invalid archived value")) {
    form.setError("archived", "Must be exactly true or false (lowercase)");
  } else throw e;
}

Prevention

When it happens

Trigger: Publishing [["archived", "True"], ["archived", "1"], or ["archived", true]] in a kind:9002 event. Note a JSON boolean true serializes to a missing/None content in some tag encoders and can instead surface as the 'must have a value' error.

Common situations: Clients mapping a UI toggle to a native boolean or an integer 0/1; language differences (Python 'True' capitalization leaking into payloads); copy-pasted payloads from APIs that use 0/1 flags.

Related errors


AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16). Data as JSON: /api/errors/845f8b08c72e487c. Report an issue: GitHub.