stride3d/stride · error · ArgumentException

This parameter must be a formattable string containing

Error message

This parameter must be a formattable string containing '{0}' and '{1}' tokens

What it means

NamingHelper.ComputeNewName generates names using a pattern that must contain both {0} (base name) and {1} (counter) placeholders. If the supplied namePattern is missing either token, the generated names could not include the required parts, so an ArgumentException naming the namePattern parameter is thrown.

Solutions

  1. Fix the pattern to include both tokens, e.g. "{0} {1}" or "{0}-{1}".
  2. Pass null to use DefaultNamePattern instead of a custom one.
  3. Validate the pattern with Contains checks before calling ComputeNewName.
  4. Catch ArgumentException and fall back to the default pattern.

Example fix

// before
NamingHelper.ComputeNewName(names, contains, "newName-")
// after
NamingHelper.ComputeNewName(names, contains, "{0}-{1}")
Defensive patterns

Strategy: validation

Validate before calling

if (pattern == null || (!pattern.Contains("{0}") || !pattern.Contains("{1}"))) pattern = null; // fall back to default
NamingHelper.ComputeNewName(existingNames, contains, pattern);

Type guard

bool IsValidNamePattern(string? p) => p == null || (p.Contains("{0}") && p.Contains("{1}"));

Try / catch

try { newName = NamingHelper.ComputeNewName(names, contains, pattern); }
catch (ArgumentException ex) when (ex.ParamName == "namePattern") { newName = NamingHelper.ComputeNewName(names, contains, null); }

Prevention

When it happens

Trigger: Passing a custom namePattern string to ComputeNewName that lacks "{0}" or "{1}" (e.g. "{name}-{count}" or a plain string).

Common situations: Hand-written rename patterns copied from other tools that use different placeholder syntax; localization or formatting changes that removed a token; defaulting code that passes empty/blank patterns.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/6f274038cb81406a. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core.Design/NamingHelper.cs:119

    /// <summary>
    /// Generate a name for a new object that is guaranteed to be unique for the provided "contains predicate". To generate such name, a base name and a pattern for variations must be provided.
    /// </summary>
    /// <param name="baseName">The base name used to generate the new name. If the name is available in the collection, it will be returned as-is. Otherwise, a name following the given pattern will be returned.</param>
    /// <param name="containsDelegate">The delegate used to determine if the asset is already existing</param>
    /// <param name="namePattern">The pattern used to generate the new name, when the base name is unavailable. This pattern must contains the token '{0}' that will be replaced by the base name, and the token '{1}' that will be replaced by the smallest numerical value that can generate an available name, starting from 2. If null, <see cref="DefaultNamePattern"/> will be used instead.</param>
    /// <returns><see cref="baseName"/> if the "contains predicate" returns false. Otherwise, a string formatted with <see cref="namePattern"/>, using <see cref="baseName"/> as token '{0}' and the smallest numerical value that can generate an available name, starting from 2</returns>
    public static string ComputeNewName(string baseName, ContainsLocationDelegate containsDelegate, string? namePattern = null)
    {
#if NET6_0_OR_GREATER
        ArgumentNullException.ThrowIfNull(baseName);
        ArgumentNullException.ThrowIfNull(containsDelegate);
#else
        if (baseName is null) throw new ArgumentNullException(nameof(baseName));
        if (containsDelegate is null) throw new ArgumentNullException(nameof(containsDelegate));
#endif
        namePattern ??= DefaultNamePattern;
        if (!namePattern.Contains("{0}") || !namePattern.Contains("{1}")) throw new ArgumentException("This parameter must be a formattable string containing '{0}' and '{1}' tokens", nameof(namePattern));

        // First check if the base name itself is ok
        if (!containsDelegate(baseName))
            return baseName;

        // Initialize counter
        var counter = 1;
        // Checks whether baseName already 'implements' the namePattern
        var match = Regex.Match(baseName, $"^{Regex.Escape(namePattern).Replace(@"\{0}", "(.*)").Replace(@"\{1}", @"(\d+)")}$");
        if (match.Success && match.Groups.Count >= 3)
        {
            // if so, extract the base name and the current counter
            var intValue = int.Parse(match.Groups[2].Value);
            // Ensure there is no leading 0 messing around
            if (intValue.ToString() == match.Groups[2].Value)
            {
                baseName = match.Groups[1].Value;
                counter = intValue;

View on GitHub (pinned to 96fad776d2)