Unity-Technologies/UnityCsReference · error · NotSupportedException
Deployment targets main thread context can only be…
Error message
Deployment targets main thread context can only be retrieved from the main thread.
What it means
Thrown by DefaultDeploymentTargetsExtension.GetMainThreadContext via CheckGetMainThreadContextCalledOnMainThread when the call is not on the Unity main thread. Deployment target discovery (ADB device enumeration on Android, etc.) is main-thread-affined because it touches native editor state. NotSupportedException signals that the operation has an inviolable precondition, not a recoverable failure.
Solutions
- Marshal the call to the main thread: wrap it in EditorApplication.delayCall or a main-thread dispatcher before invoking the deployment API.
- Restructure async code to do the DeploymentTargetManager work synchronously on the main thread and only offload non-Unity work to background tasks.
- If you control the entry point, assert InternalEditorUtility.CurrentThreadIsMainThread() at the top of the method that leads here.
Example fix
// before
await Task.Run(() => manager.GetKnownTargets());
// after
List<DeploymentTargetIdAndStatus> targets = null;
EditorApplication.delayCall += () => { targets = manager.GetKnownTargets(); }; Defensive patterns
Strategy: validation
Validate before calling
if (!UnityEngine.InternalEditorUtility.CurrentThreadIsMainThread())
throw new InvalidOperationException("Must be on main thread");
// or marshal:
// EditorApplication.delayCall += () => DoDeploymentWork(); Try / catch
try { ctx = ext.GetMainThreadContext(setup); }
catch (NotSupportedException ex) when (ex.Message.Contains("main thread"))
{ /* re-dispatch to main thread via EditorApplication.delayCall */ } Prevention
- Assume all DeploymentTargetManager APIs are main-thread-affined.
- Do not await between fetching the context and using it.
- Assert main-thread at the entry point of any build/deployment routine.
When it happens
Trigger: Calling any DeploymentTargetManager API that internally calls GetMainThreadContext (e.g. constructing DeploymentTargetManager, GetKnownTargets) from a Task, a ThreadPool callback, or a background thread without marshalling back to the main thread.
Common situations: Build pipeline running device deployment steps on a background task; a CI script invoking deployment target enumeration off the main thread; async/await continuation that lost the main thread synchronization context after an await.
Related errors
- Platform does not implement DeploymentTargetsExtension
- can only be created on the main thread
- The build cannot be appended.
- A mode named already exists in section
- AA is not supported on GUIViews
AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13).
Data as JSON: /api/errors/4308e6e994992bf3.
Report an issue: GitHub.
Appendix: source
Thrown at Editor/Mono/DeploymentTargets/DefaultDeploymentTargetsExtension.cs:61
internal override void Stop() {}
internal override void Clear() {}
}
internal abstract class DefaultDeploymentTargetsExtension
: IDeploymentTargetsExtension
{
public virtual IDeploymentTargetsMainThreadContext GetMainThreadContext(bool setup)
{
CheckGetMainThreadContextCalledOnMainThread();
return new DefaultDeploymentTargetsMainThreadContext();
}
protected void CheckGetMainThreadContextCalledOnMainThread()
{
if (!InternalEditorUtility.CurrentThreadIsMainThread())
throw new NotSupportedException("Deployment targets main thread context can only be retrieved from the main thread.");
}
public virtual List<DeploymentTargetIdAndStatus> GetKnownTargets(IDeploymentTargetsMainThreadContext context, ProgressHandler progressHandler = null)
{
return new List<DeploymentTargetIdAndStatus>();
}
public virtual IDeploymentTargetInfo GetTargetInfo(IDeploymentTargetsMainThreadContext context, DeploymentTargetId targetId, ProgressHandler progressHandler = null)
{
return new DefaultDeploymentTargetInfo();
}
public virtual DeploymentTargetLogger GetTargetLogger(IDeploymentTargetsMainThreadContext context, DeploymentTargetId targetId)
{
return new DefaultDeploymentTargetLogger();
}
public virtual IDeploymentLaunchResult LaunchBuildOnTarget(IDeploymentTargetsMainThreadContext context, BuildProperties buildProperties, DeploymentTargetId targetId, ProgressHandler progressHandler = null)View on GitHub (pinned to 225b0fbdb5)