Unity-Technologies/ml-agents · error · UnityAgentsException
StatsSideChannel should never receive messages.
Error message
StatsSideChannel should never receive messages.
What it means
StatsSideChannel is a write-only channel: Unity pushes training statistics to Python and never consumes incoming messages. Its OnMessageReceived override unconditionally throws UnityAgentsException to assert this contract. Receiving any message on this channel id means the Python side is sending data on a channel reserved for Unity output.
Source
Thrown at com.unity.ml-agents/Runtime/SideChannels/StatsSideChannel.cs:40
/// </summary>
/// <param name="key">The stat name.</param>
/// <param name="value">The stat value.</param>
/// <param name="aggregationMethod">How multiple values should be treated.</param>
public void AddStat(string key, float value, StatAggregationMethod aggregationMethod)
{
using (var msg = new OutgoingMessage())
{
msg.WriteString(key);
msg.WriteFloat32(value);
msg.WriteInt32((int)aggregationMethod);
QueueMessageToSend(msg);
}
}
/// <inheritdoc/>
protected override void OnMessageReceived(IncomingMessage msg)
{
throw new UnityAgentsException("StatsSideChannel should never receive messages.");
}
}
}
View on GitHub (pinned to 3ecb446f75)
Solutions
- Remove Python code that sends messages on the StatsSideChannel channel id; stats flow Unity -> Python only.
- If you need Unity->Python custom messages, create a new SideChannel pair with its own unique GUID on both sides.
- Audit the Python side channel registration to confirm the stats GUID isn't attached to a send path.
Example fix
# before
stats_channel.send_raw_message(...) # Python sending on stats GUID: forbidden
# after
class MyRequestChannel(SideChannel):
channel_id = uuid.UUID("<new-unique-guid>")
my_channel = MyRequestChannel()
env.reset()
# communicate via my_channel instead Defensive patterns
Strategy: validation
Validate before calling
# Python: never attach a send path to the stats channel GUID assert not any(c.channel_id == STATS_CHANNEL_GUID for c in sending_channels)
Prevention
- Treat StatsSideChannel as write-only (Unity -> Python)
- Create a dedicated GUID pair for any Python -> Unity messages
- Never reuse built-in channel GUIDs for custom traffic
When it happens
Trigger: Python code writing to the stats side channel GUID (via a custom SideChannel in mlagents-envs with the StatsSideChannel channel id) so Unity receives an incoming message on StatsSideChannel and throws.
Common situations: A custom Python tool echoing messages back on the stats channel id; wiring the wrong channel object on the Python side so stats GUID is used bidirectionally; a bug in custom interop code reusing built-in channel GUIDs for requests.
Related errors
- There was a problem reading a message in a SideChannel. Plea
- A side channel with id {channelId} is already registered. Yo
- Index out of bounds, expected a number between 0 and {Length
- Enumerator not started.
- Enumerator has reached the end already.
AI-assisted analysis of Unity-Technologies/ml-agents@3ecb446f75 (2026-09-02).
Data as JSON: /api/errors/a8ab544c3722d8aa.
Report an issue: GitHub.