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

  1. Remove Python code that sends messages on the StatsSideChannel channel id; stats flow Unity -> Python only.
  2. If you need Unity->Python custom messages, create a new SideChannel pair with its own unique GUID on both sides.
  3. 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

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


AI-assisted analysis of Unity-Technologies/ml-agents@3ecb446f75 (2026-09-02). Data as JSON: /api/errors/a8ab544c3722d8aa. Report an issue: GitHub.