Hmbown/CodeWhale · error
invalid or duplicate notification event
Error message
invalid or duplicate notification event
What it means
This error is thrown by NotificationConfigUpdate::validate when any entry in an EventSoundEvents list is not a recognized notification event name, or when the same event name appears more than once in the list. NotificationEvent::parse must accept each name, and each must be unique within the list.
Solutions
- Check each name against the accepted NotificationEvent names (exact match, correct spelling/case).
- Deduplicate the list before constructing the update.
- If an event name was renamed in a newer version, update the config to the new name.
- Use NotificationEvent::parse in your own code to validate names before building the list.
Example fix
// before NotificationConfigUpdate::EventSoundEvents(vec!["turn-complete".into(), "turn-complete".into()]) // after NotificationConfigUpdate::EventSoundEvents(vec!["turn-complete".into(), "error".into()])
Defensive patterns
Strategy: validation
Validate before calling
fn valid_event_names(events: &[String]) -> bool {
events.iter().all(|e| NotificationEvent::parse(e).is_some())
&& events.iter().collect::<std::collections::HashSet<_>>().len() == events.len()
} Prevention
- Validate each name with NotificationEvent::parse before building the list
- Copy event names exactly (case-sensitive) from the documented set
- Deduplicate lists before persisting
- Watch for renamed events across library versions
When it happens
Trigger: Constructing NotificationConfigUpdate::EventSoundEvents with a list containing an unrecognized event string (e.g. a typo like "turn_complte") or a duplicated name, then calling validate() via value(), persist_for_profile(), edit_extras(), or apply_update().
Common situations: Hand-edited config with misspelled event names; case mismatches (parser is exact); a generator appends events without checking for existing entries, producing duplicates; event names renamed between versions.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- MCP server ' ' already exists in . Use `codewhale mcp…
- a CNB access token is not configured in the Codewhale…
- account_agent_model_unconfigured
- active profile is missing or malformed
- advisor model ` ` resolved only to a custom provider kind…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1f1d237a2604db05.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/notifications.rs:313
pub fn validate(&self) -> Result<()> {
match self {
Self::ThresholdSecs(v) | Self::EventSoundMinIntervalMs(v) => anyhow::ensure!(
*v <= i64::MAX as u64,
"notification integer exceeds TOML range"
),
Self::SoundFile(path) => {
let value = path.to_str().context("sound path must be UTF-8")?;
anyhow::ensure!(
!value.is_empty()
&& value.len() <= 4096
&& !value.chars().any(char::is_control),
"invalid sound path"
);
}
Self::EventSoundEvents(events) => {
anyhow::ensure!(events.len() <= 6, "too many notification events");
for (index, event) in events.iter().enumerate() {
anyhow::ensure!(
NotificationEvent::parse(event).is_some()
&& !events[..index].contains(event),
"invalid or duplicate notification event"
);
}
}
_ => (),
}
Ok(())
}
pub fn value(&self) -> Result<Option<toml::Value>> {
self.validate()?;
Ok(Some(match self {
Self::Method(value) => value.as_str().into(),
Self::Sound(Some(value)) | Self::CompletionSound(value) => value.as_str().into(),
Self::Sound(None) => return Ok(None),
Self::Condition(value) => value.as_str().into(),
Self::SubagentCompletion(value) => value.as_str().into(),View on GitHub (pinned to 73e0f67d83)