astrid-runtime/astrid · error
a topic is required (positional ` ` or `--topic `)
Error message
a topic is required (positional `<topic>` or `--topic <topic>`)
What it means
Resolution guard in Args::resolve_topic: neither the positional `<topic>` argument nor the `--topic` flag was supplied. clap's conflicts_with already rejects supplying both, so this error exclusively covers the neither-supplied case. Emitting an event requires exactly one topic to build the `{host}.v1.hook.{session}.{event}` topic name.
Solutions
- Pass the topic positionally, e.g. astrid-emit sage.v1.hook.before_tool_call
- Or pass it as a flag: astrid-emit --topic sage.v1.hook.before_tool_call
- Check the wrapper script or host hook config that dropped the topic argument
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/astrid-emit/src/lib.rs:141 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/248f05a958a1174e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-emit/src/lib.rs:141
Ok(format!("{host}.v1.hook.{session}.{event}"))
}
impl Args {
/// Resolve the single topic from whichever form was supplied.
///
/// `clap`'s `conflicts_with` already rejects supplying both, so the
/// only failure this surfaces is supplying neither.
///
/// # Errors
///
/// Returns an error if no topic was supplied (neither positional
/// nor `--topic`).
pub fn resolve_topic(self) -> Result<String> {
match (self.topic_positional, self.topic_flag) {
(Some(t), None) | (None, Some(t)) => Ok(t),
(None, None) => {
anyhow::bail!("a topic is required (positional `<topic>` or `--topic <topic>`)")
},
// Unreachable in practice: clap's `conflicts_with` rejects
// both-supplied before we get here. Kept exhaustive so the
// match doesn't rely on that invariant silently.
(Some(_), Some(_)) => {
anyhow::bail!("specify the topic exactly once (positional OR --topic, not both)")
},
}
}
}
/// Outcome of an [`emit`] call: what to print to stderr (if anything)
/// and which process exit code to return. The fixed `{"continue":true}`
/// stdout line is the caller's responsibility and is emitted
/// unconditionally regardless of this outcome.
#[derive(Debug)]
#[must_use]
pub struct Outcome {View on GitHub (pinned to affd8760f4)