{"record":{"id":"a2c8936aebb75a72","repo":"nautechsystems/nautilus_trader","slug":"key-value-contained-invalid-characters-was-v","errorCode":null,"errorMessage":"{key} `value` contained invalid characters, was {value}","messagePattern":"(.+?) `value` contained invalid characters, was (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/common/src/msgbus/mstr.rs","lineNumber":55,"sourceCode":"///\n/// - `MStr<Pattern>` - for subscriptions, allows wildcards (`*`, `?`)\n/// - `MStr<Topic>` - for publishing, no wildcards\n/// - `MStr<Endpoint>` - for direct messages, no wildcards\n#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]\n#[serde(transparent)]\npub struct MStr<T> {\n    value: Ustr,\n    #[serde(skip)]\n    _marker: std::marker::PhantomData<T>,\n}\n\nimpl<T> MStr<T> {\n    #[inline(always)]\n    fn checked(value: Ustr, key: &str) -> anyhow::Result<Self> {\n        check_valid_string_utf8(value, stringify!(value))?;\n\n        if value.as_bytes().iter().any(|&b| b == b'*' || b == b'?') {\n            anyhow::bail!(\"{key} `value` contained invalid characters, was {value}\");\n        }\n\n        Ok(Self {\n            value,\n            _marker: std::marker::PhantomData,\n        })\n    }\n}\n\nimpl<T> Display for MStr<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.value)\n    }\n}\n\nimpl<T> Deref for MStr<T> {\n    type Target = Ustr;\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/msgbus/mstr.rs#L37-L73","documentation":"MStr::checked validates that the underlying Ustr for a typed message-topic string contains only valid UTF-8 and none of the wildcard characters `*` or `?`. Topics are pattern-matched internally, so wildcard characters in a stored MStr would corrupt matching; the code bails with this message naming the key type.","triggerScenarios":"Constructing any MStr<T> typed constructor (e.g. MStr::topic or MStr::endpoint) with a string containing `*` or `?`, or with non-UTF-8 bytes (via check_valid_string_utf8, which raises its own error).","commonSituations":"Building topics from user-supplied subscription patterns like 'data.quotes.*' instead of subscribing via a wildcard pattern API; config files where glob-style topic filters are pasted into topic fields; copied topic strings including pattern suffixes.","solutions":["Remove `*` and `?` from the string before constructing the MStr.","Use the wildcard-aware subscribe/pattern API instead of embedding wildcards in a topic value.","Validate/sanitize user-provided topic config values before creating MStr instances."],"exampleFix":"// before\nlet topic = MStr::<Topic>::new(\"data.quotes.*\")?;\n// after\nlet topic = MStr::<Topic>::new(\"data.quotes\")?;\n// subscribe with pattern instead\nmsgbus.subscribe_pattern(\"data.quotes.*\", handler);","handlingStrategy":"validation","validationCode":"def make_mstr(value: str) -> str:\n    if any(ch in value for ch in \"*?\"):\n        raise ValueError(f\"topic value must not contain wildcards: {value!r}\")\n    return value","typeGuard":null,"tryCatchPattern":"match MStr::<Topic>::new(user_value) {\n    Ok(t) => use(t),\n    Err(e) => log::warn!(\"invalid topic string: {e}\"),\n}","preventionTips":["Never embed glob wildcards in topic values; use pattern-subscription APIs instead.","Sanitize config-sourced topic strings at load time.","Add a unit test that rejects wildcard characters in all topic-building helpers."],"tags":["validation","topic","message-bus","wildcard"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}