Cysharp/UniTask · error · NotSupportedException
Use ForEachAwaitAsync instead.
Error message
Use ForEachAwaitAsync instead.
What it means
Thrown (and emitted as a compile-time error via [Obsolete(..., true)]) by the ForEachAsync extension on IUniTaskAsyncEnumerable<T> taking Func<T, UniTask>. This overload was removed because the name 'ForEachAsync' was ambiguous about whether the async action is awaited per-element. The replacement is ForEachAwaitAsync which makes the await semantics explicit.
Source
Thrown at src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/ForEach.cs:30
Error.ThrowArgumentNullException(action, nameof(action));
return Cysharp.Threading.Tasks.Linq.ForEach.ForEachAsync(source, action, cancellationToken);
}
public static UniTask ForEachAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource, Int32> action, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
return Cysharp.Threading.Tasks.Linq.ForEach.ForEachAsync(source, action, cancellationToken);
}
/// <summary>Obsolete(Error), Use Use ForEachAwaitAsync instead.</summary>
[Obsolete("Use ForEachAwaitAsync instead.", true)]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static UniTask ForEachAsync<T>(this IUniTaskAsyncEnumerable<T> source, Func<T, UniTask> action, CancellationToken cancellationToken = default)
{
throw new NotSupportedException("Use ForEachAwaitAsync instead.");
}
/// <summary>Obsolete(Error), Use Use ForEachAwaitAsync instead.</summary>
[Obsolete("Use ForEachAwaitAsync instead.", true)]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static UniTask ForEachAsync<T>(this IUniTaskAsyncEnumerable<T> source, Func<T, int, UniTask> action, CancellationToken cancellationToken = default)
{
throw new NotSupportedException("Use ForEachAwaitAsync instead.");
}
public static UniTask ForEachAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> action, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
return Cysharp.Threading.Tasks.Linq.ForEach.ForEachAwaitAsync(source, action, cancellationToken);
}
View on GitHub (pinned to ceac8d6946)
Solutions
- Rename the call from ForEachAsync to ForEachAwaitAsync (same signature).
- If the action is synchronous (Func<T, void>), use the non-generic ForEachAsync overload that accepts a synchronous action — that overload is not obsolete.
Example fix
// before await source.ForEachAsync(async x => await ProcessAsync(x)); // after await source.ForEachAwaitAsync(async x => await ProcessAsync(x));
Defensive patterns
Strategy: validation
Validate before calling
// This is a compile-time error — fix at the call site. // Replace ForEachAsync with ForEachAwaitAsync for async actions: await source.ForEachAwaitAsync(async x => await ProcessAsync(x)); // For synchronous actions, the non-obsolete overload is fine: await source.ForEachAsync(x => ProcessSync(x));
Prevention
- When upgrading UniTask, search your codebase for 'ForEachAsync' and migrate to ForEachAwaitAsync.
- Bookmark the current UniTask API docs to avoid referencing outdated examples.
When it happens
Trigger: Calling source.ForEachAsync(async x => await ProcessAsync(x)) on an IUniTaskAsyncEnumerable<T>. The [Obsolete(true)] attribute makes this a hard compile error; the runtime throw is a fallback for reflection/dynamic invocation.
Common situations: Upgrading UniTask from a version that had this overload. Copying code from outdated tutorials or Stack Overflow answers. Migration from System.Threading.Tasks extensions where ForEachAsync is the standard name.
AI-assisted analysis of Cysharp/UniTask@ceac8d6946 (2026-08-13).
Data as JSON: /api/errors/d5e11f83e544cce3.
Report an issue: GitHub.