Unity-Technologies/UnityCsReference · error · ArgumentException

The component {typeof(T).Name} already exists in the build p

Error message

The component {typeof(T).Name} already exists in the build profile {name}.

What it means

Thrown by BuildProfile.CreateComponent<T>() when a sub-asset component of the same type T already exists on the build profile. Unity's BuildProfile enforces a one-component-per-type invariant, so attempting to create a duplicate is rejected with an ArgumentException. The check delegates to GetComponent<T>() first, and only creates a new ScriptableObject instance if none is found.

Source

Thrown at Editor/Mono/BuildProfile/BuildProfile.API.cs:54

                return;

            BuildProfileModuleUtil.SwitchLegacyActiveFromBuildProfile(buildProfile);
        }

        /// <summary>
        /// Instantiates a new component of type T and adds it as a sub-asset to the build profile.
        /// </summary>
        /// <returns>Returns the newly created ScriptableObect.</returns>
        /// <exception cref="ArgumentException">
        /// Thrown when a sub asset of the same type already exists in the build profile.
        /// </exception>
        [VisibleToOtherModules]
        public T CreateComponent<T>() where T : UnityEngine.Object
        {
            var found = GetComponent<T>();
            if (found != null)
            {
                throw new ArgumentException($"The component {typeof(T).Name} already exists in the build profile {name}.");
            }

            var type = typeof(T);
            if (type.IsSubclassOf(typeof(ScriptableObject)))
            {
                var objectToAdd = ScriptableObject.CreateInstance(type);
                objectToAdd.hideFlags = HideFlags.HideInHierarchy;
                objectToAdd.name = type.Name;
                AssetDatabase.AddObjectToAsset(objectToAdd, this);
                return objectToAdd as T;
            }

            throw new ArgumentException($"Type {type.Name} is not a ScriptableObject or a supported settings object type.");
        }

        /// <summary>
        /// Gets a component of type T associated with the build profile, its global fallback,
        /// or null if the component is not available.

View on GitHub (pinned to 225b0fbdb5)

Solutions

  1. Call GetComponent<T>() first and only call CreateComponent<T>() when it returns null.
  2. If you intend to replace, call RemoveComponent<T>() (or ForceRemoveComponent<T>() for required components) before CreateComponent<T>().
  3. Audit the calling code to prevent the CreateComponent call from running more than once per profile (e.g. guard with a flag or existence check).

Example fix

// before
profile.CreateComponent<MySettings>();

// after
if (profile.GetComponent<MySettings>() == null)
    profile.CreateComponent<MySettings>();
Defensive patterns

Strategy: validation

Validate before calling

if (profile.GetComponent<T>() != null) { /* already exists; skip or replace */ }

Type guard

static bool HasComponent<P,T>(P profile) where P : BuildProfile where T : UnityEngine.Object => profile.GetComponent<T>() != null;

Prevention

When it happens

Trigger: Calling CreateComponent<T>() when GetComponent<T>() already returns a non-null instance for the same type T on the same BuildProfile. Common when initialization code runs twice or a component was created via AddComponent or deserialization previously.

Common situations: Re-running editor setup/initialization scripts that create components without checking existence first; migrating build profiles that already carry deserialized components; calling CreateComponent inside a loop or repeated editor callback.

Related errors


AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13). Data as JSON: /api/errors/c18dd24fdabf9aff. Report an issue: GitHub.