{"record":{"id":"221a5ea5061c6124","repo":"Unity-Technologies/ml-agents","slug":"channel-value-ch-must-be-in-range-0-m-tensors","errorCode":null,"errorMessage":"channel value {ch} must be in range [0, {m_TensorShape.Channels() - 1}]","messagePattern":"channel value (.+?) must be in range \\[0, (.+?)\\]","errorType":"validation","errorClass":"IndexOutOfRangeException","httpStatus":null,"severity":"error","filePath":"com.unity.ml-agents/Runtime/Sensors/ObservationWriter.cs","lineNumber":152,"sourceCode":"        public float this[int ch, int h, int w]\n        {\n            set\n            {\n                if (m_Data != null)\n                {\n                    if (h < 0 || h >= m_TensorShape.Height())\n                    {\n                        throw new IndexOutOfRangeException($\"height value {h} must be in range [0, {m_TensorShape.Height() - 1}]\");\n                    }\n\n                    if (w < 0 || w >= m_TensorShape.Width())\n                    {\n                        throw new IndexOutOfRangeException($\"width value {w} must be in range [0, {m_TensorShape.Width() - 1}]\");\n                    }\n\n                    if (ch < 0 || ch >= m_TensorShape.Channels())\n                    {\n                        throw new IndexOutOfRangeException($\"channel value {ch} must be in range [0, {m_TensorShape.Channels() - 1}]\");\n                    }\n\n                    var index = m_TensorShape.Index(m_Batch, ch + m_Offset, h, w);\n                    m_Data[index] = value;\n                }\n                else\n                {\n                    if (ch + m_Offset < 0 || ch + m_Offset >= m_TensorShape.Channels() ||\n                        h < 0 || h >= m_TensorShape.Height() ||\n                        w < 0 || w >= m_TensorShape.Width())\n                        return;\n\n                    m_Proxy.data.CompleteAllPendingOperations();\n                    ((Tensor<float>)m_Proxy.data)[m_Batch, ch + m_Offset, h, w] = value;\n                }\n            }\n        }\n","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/Unity-Technologies/ml-agents/blob/3ecb446f75d1e7400eb404c562dc005d3164cffc/com.unity.ml-agents/Runtime/Sensors/ObservationWriter.cs#L134-L170","documentation":"ObservationWriter's indexed setter validates that the channel coordinate falls within the observation tensor's channel count before writing. Writing outside that range would overwrite neighboring observations in the flat backing array, so an IndexOutOfRangeException is thrown.","triggerScenarios":"A custom sensor's Write() implementation calling Write(h, w, ch, value) with ch < 0 or ch >= channel count (e.g. writing RGB with 3 channels while the spec declares 1 channel, or writing a 4-channel RGBA loop); m_Offset plus ch exceeding the declared channels.","commonSituations":"Custom sensors writing RGBA into a grayscale observation; stacked sensors where the offset wasn't accounted for; changing channel count in the spec but not in the write loop.","solutions":["Limit the channel loop to spec.Channels() (and respect the writer's offset for stacked writers)","Make the ObservationSpec channel count match the data written (e.g. 3 for RGB, 1 for grayscale)","Use ObservationWriter helper APIs (WriteTex2D/Add) that handle channels and offsets correctly","Check for off-by-one loops (ch <= channels instead of ch < channels)"],"exampleFix":"// before\nfor (int ch = 0; ch < 4; ch++) writer[0, 0, ch] = rgba[ch]; // spec has 3 channels\n// after\nfor (int ch = 0; ch < obsSpec.Channels(); ch++) writer[0, 0, ch] = rgba[ch];","handlingStrategy":"validation","validationCode":"// Unity C#: in custom sensor Write\nif (ch < 0 || ch >= obsSpec.Channels())\n{\n    Debug.LogError($\"ch={ch} outside [0,{obsSpec.Channels() - 1}]\");\n    return;\n}\nwriter[h, w, ch] = value;","typeGuard":null,"tryCatchPattern":"try\n{\n    writer[h, w, ch] = value;\n}\ncatch (IndexOutOfRangeException e) when (e.Message.Contains(\"channel value\"))\n{\n    Debug.LogError(\"Channel out of bounds writing observation: \" + e.Message);\n}","preventionTips":["Limit channel loops to spec.Channels() (RGB=3, grayscale=1) and respect the writer offset","Keep the ObservationSpec channel count in sync with the data actually written","Use ObservationWriter helper methods (WriteTex2D/Add) that handle channels and offsets"],"tags":["unity","ml-agents","observation-writer","bounds","index-out-of-range"],"backgroundTag":"index-out-of-range","analyzedSha":"3ecb446f75d1e7400eb404c562dc005d3164cffc","analyzedAt":"2026-09-02T16:33:12.832Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}