{"record":{"id":"0dbf3d04e0055ffe","repo":"livekit/livekit","slug":"dependencydescriptorreader-invalid-spatial-layer","errorCode":null,"errorMessage":"DependencyDescriptorReader: invalid spatial layer, should be less than the number of resolutions","messagePattern":"DependencyDescriptorReader: invalid spatial layer, should be less than the number of resolutions","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/sfu/rtpextension/dependencydescriptor/dependencydescriptorreader.go","lineNumber":28,"sourceCode":"// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage dependencydescriptor\n\nimport (\n\t\"errors\"\n)\n\nvar (\n\tErrDDReaderNoStructure              = errors.New(\"DependencyDescriptorReader: Structure is nil\")\n\tErrDDReaderTemplateWithoutStructure = errors.New(\"DependencyDescriptorReader: has templateDependencyStructurePresentFlag but AttachedStructure is nil\")\n\tErrDDReaderTooManyTemplates         = errors.New(\"DependencyDescriptorReader: too many templates\")\n\tErrDDReaderTooManyTemporalLayers    = errors.New(\"DependencyDescriptorReader: too many temporal layers\")\n\tErrDDReaderTooManySpatialLayers     = errors.New(\"DependencyDescriptorReader: too many spatial layers\")\n\tErrDDReaderInvalidTemplateIndex     = errors.New(\"DependencyDescriptorReader: invalid template index\")\n\tErrDDReaderInvalidSpatialLayer      = errors.New(\"DependencyDescriptorReader: invalid spatial layer, should be less than the number of resolutions\")\n\tErrDDReaderNumDTIMismatch           = errors.New(\"DependencyDescriptorReader: decode target indications length mismatch with structure num decode targets\")\n\tErrDDReaderNumChainDiffsMismatch    = errors.New(\"DependencyDescriptorReader: chain diffs length mismatch with structure num chains\")\n)\n\ntype DependencyDescriptorReader struct {\n\t// Output.\n\tdescriptor *DependencyDescriptor\n\n\t// Values that are needed while reading the descriptor, but can be discarded\n\t// when reading is complete.\n\tbuffer                         *BitStreamReader\n\tframeDependencyTemplateId      int\n\tactiveDecodeTargetsPresentFlag bool\n\tcustomDtisFlag                 bool\n\tcustomFdiffsFlag               bool\n\tcustomChainsFlag               bool\n\tstructure                      *FrameDependencyStructure\n}","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/livekit/livekit/blob/ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6/pkg/sfu/rtpextension/dependencydescriptor/dependencydescriptorreader.go#L10-L46","documentation":"ErrDDReaderInvalidSpatialLayer is returned by readFrameDependencyDefinition when the frame's spatial_id is greater than or equal to the number of resolutions declared in the structure. The spatial layer referenced by the frame does not exist in the declared resolution set, so frame dependencies cannot be interpreted. The bit reader buffer is invalidated before returning.","triggerScenarios":"Parsing a dependency descriptor whose FrameDependencies.SpatialId >= len(structure.Resolutions); happens when the publisher adds a spatial layer (e.g. enables simulcast/SVC) without updating the attached structure, or a structure-bearing packet was lost.","commonSituations":"SVC/simulcast streams where the encoder changes layer count mid-stream; clients that cached an old structure with fewer resolutions; interoperability with encoders that emit out-of-range spatial IDs.","solutions":["Ensure the keyframe carrying the updated structure (with all resolutions) is transmitted and not dropped","Treat as transient during layer changes; skip the packet and wait for the next structure refresh","Verify encoder configuration keeps spatial layer count consistent with the declared structure","Log at debug/info only, as livekit's parser does, to avoid noise for expected transient cases"],"exampleFix":"// before\nres, err := parseDD(payload)\nif err != nil { return err }\n// after\nres, err := parseDD(payload)\nif err == dd.ErrDDReaderInvalidSpatialLayer {\n    // stale structure; wait for next keyframe/structure\n    return nil\n} else if err != nil { return err }","handlingStrategy":"validation","validationCode":"func validSpatialLayer(dd *dd.DependencyDescriptor, structure *dd.Structure) bool {\n    return structure != nil && int(dd.FrameDependencies.SpatialId) < len(structure.Resolutions)\n}","typeGuard":"func isDDInvalidSpatialLayer(err error) bool {\n    return errors.Is(err, dd.ErrDDReaderInvalidSpatialLayer)\n}","tryCatchPattern":"if _, err := reader.Parse(buf); err != nil {\n    if errors.Is(err, dd.ErrDDReaderInvalidSpatialLayer) {\n        return nil // stale structure; skip until re-sync\n    }\n    return err\n}","preventionTips":["Keep the declared Resolutions list in sync with the encoder's active spatial layers","Send a structure-carrying keyframe whenever layer count changes","Avoid dropping packets flagged with templateDependencyStructurePresentFlag"],"tags":["webrtc","rtp","svc","simulcast","dependency-descriptor"],"backgroundTag":"rtp-dependency-descriptor-invalid-template-index","analyzedSha":"ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6","analyzedAt":"2026-09-02T03:56:08.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}