rustfs/rustfs · error · TargetIDError

Invalid TargetID format '{0}', expect 'ID:Name'

Error message

Invalid TargetID format '{0}', expect 'ID:Name'

What it means

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.

Source

Thrown at crates/targets/src/arn.rs:24

//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::TargetError;
use rustfs_config::notify::{ARN_PREFIX, DEFAULT_ARN_PARTITION, DEFAULT_ARN_SERVICE};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::str::FromStr;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum TargetIDError {
    #[error("Invalid TargetID format '{0}', expect 'ID:Name'")]
    InvalidFormat(String),
}

/// Target ID, used to identify notification targets
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct TargetID {
    pub id: String,
    pub name: String,
}

impl TargetID {
    pub fn new(id: String, name: String) -> Self {
        Self { id, name }
    }

    /// Create an ARN
    pub fn to_arn(&self, region: &str) -> ARN {
        ARN {

View on GitHub (pinned to 35af688cd9)

Solutions

  1. 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.
  2. If the ID arrives from tooling, validate it with split_once(':') (see validationCode) before writing it to config.
  3. 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.

Example fix

// before (config.json)
//   "targets": ["1"]
let id: TargetID = serde_json::from_str("\"1\"")?; // Invalid TargetID format '1'

// after (config.json)
//   "targets": ["1:webhook"]
let id: TargetID = serde_json::from_str("\"1:webhook\"")?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_target_id(s: &str) -> bool {
    match s.split_once(':') {
        Some((id, name)) => !id.is_empty() && !name.is_empty(),
        None => false,
    }
}
anyhow::ensure!(valid_target_id(raw), "target id must be 'ID:Name', got '{raw}'");

Type guard

fn is_invalid_target_id(e: &TargetIDError) -> bool {
    matches!(e, TargetIDError::InvalidFormat(_))
}

Try / catch

match raw.parse::<TargetID>() {
    Ok(id) => id,
    Err(TargetIDError::InvalidFormat(bad)) => {
        return Err(anyhow!("notification target '{bad}' must be 'ID:Name'"));
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of rustfs/rustfs@35af688cd9 (2026-08-20). Data as JSON: /api/errors/5e64a7ec7ea9077e. Report an issue: GitHub.