{"record":{"id":"5e64a7ec7ea9077e","repo":"rustfs/rustfs","slug":"invalid-targetid-format-0-expect-id-name","errorCode":null,"errorMessage":"Invalid TargetID format '{0}', expect 'ID:Name'","messagePattern":"Invalid TargetID format '(.+?)', expect 'ID:Name'","errorType":"validation","errorClass":"TargetIDError","httpStatus":null,"severity":"error","filePath":"crates/targets/src/arn.rs","lineNumber":24,"sourceCode":"//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nuse crate::TargetError;\nuse rustfs_config::notify::{ARN_PREFIX, DEFAULT_ARN_PARTITION, DEFAULT_ARN_SERVICE};\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::fmt;\nuse std::str::FromStr;\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\npub enum TargetIDError {\n    #[error(\"Invalid TargetID format '{0}', expect 'ID:Name'\")]\n    InvalidFormat(String),\n}\n\n/// Target ID, used to identify notification targets\n#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]\npub struct TargetID {\n    pub id: String,\n    pub name: String,\n}\n\nimpl TargetID {\n    pub fn new(id: String, name: String) -> Self {\n        Self { id, name }\n    }\n\n    /// Create an ARN\n    pub fn to_arn(&self, region: &str) -> ARN {\n        ARN {","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/rustfs/rustfs/blob/35af688cd9d41b4346fbe27dcf7250ba72046c1f/crates/targets/src/arn.rs#L6-L42","documentation":"TargetIDError::InvalidFormat is returned by TargetID::from_str (crates/targets/src/arn.rs:60-70) when the input contains no ':' at all — parsing is splitn(2, ':'), so any string with at least one colon succeeds (empty id or name passes; extra colons remain in the name). It reaches user code mainly through serde: TargetID::deserialize (lines 82-90) funnels it into serde::de::Error::custom, so a malformed notification-target entry in config JSON surfaces with this message at load time.","triggerScenarios":"Deserializing a notify/bucket-notification config where a target is written as \"1\" instead of \"1:webhook\"; calling TargetID::from_str or \"...\".parse::<TargetID>() on an ID without the 'ID:Name' separator; round-tripping a TargetID through string manipulation that drops the colon.","commonSituations":"Hand-edited rustfs notification configs after renaming targets; automation emitting just the numeric target id; migration scripts that split/rejoin ARN fields incorrectly. The error text shows the offending string verbatim, which makes the offending config key easy to spot.","solutions":["Fix the config entry to the 'ID:Name' form, e.g. \"1:webhook\" — the value before the first colon is the id, everything after is the name.","If the ID arrives from tooling, validate it with split_once(':') (see validationCode) before writing it to config.","When the string is meant to be a full ARN, use ARN::from_str instead — TargetID::from_str only accepts the bare 'ID:Name' component."],"exampleFix":"// before (config.json)\n//   \"targets\": [\"1\"]\nlet id: TargetID = serde_json::from_str(\"\\\"1\\\"\")?; // Invalid TargetID format '1'\n\n// after (config.json)\n//   \"targets\": [\"1:webhook\"]\nlet id: TargetID = serde_json::from_str(\"\\\"1:webhook\\\"\")?;","handlingStrategy":"validation","validationCode":"fn valid_target_id(s: &str) -> bool {\n    match s.split_once(':') {\n        Some((id, name)) => !id.is_empty() && !name.is_empty(),\n        None => false,\n    }\n}\nanyhow::ensure!(valid_target_id(raw), \"target id must be 'ID:Name', got '{raw}'\");","typeGuard":"fn is_invalid_target_id(e: &TargetIDError) -> bool {\n    matches!(e, TargetIDError::InvalidFormat(_))\n}","tryCatchPattern":"match raw.parse::<TargetID>() {\n    Ok(id) => id,\n    Err(TargetIDError::InvalidFormat(bad)) => {\n        return Err(anyhow!(\"notification target '{bad}' must be 'ID:Name'\"));\n    }\n}","preventionTips":["Validate 'ID:Name' shape in config editors/linters before deploy.","Generate target entries through TargetID::new + Serialize rather than hand-writing strings.","Remember splitn(2, ':'): extra colons land in the name — encode names without colons to keep round-trips clean."],"tags":["rust","rustfs","notification","targets","config","arn","serde"],"backgroundTag":"invalid-target-id-format","analyzedSha":"35af688cd9d41b4346fbe27dcf7250ba72046c1f","analyzedAt":"2026-08-20T21:57:04.799Z","contentChangedAt":"2026-08-20T21:57:04.799Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}