livekit/livekit · warning
DependencyDescriptorReader: invalid spatial layer, should be
Error message
DependencyDescriptorReader: invalid spatial layer, should be less than the number of resolutions
What it means
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.
Source
Thrown at pkg/sfu/rtpextension/dependencydescriptor/dependencydescriptorreader.go:28
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package dependencydescriptor
import (
"errors"
)
var (
ErrDDReaderNoStructure = errors.New("DependencyDescriptorReader: Structure is nil")
ErrDDReaderTemplateWithoutStructure = errors.New("DependencyDescriptorReader: has templateDependencyStructurePresentFlag but AttachedStructure is nil")
ErrDDReaderTooManyTemplates = errors.New("DependencyDescriptorReader: too many templates")
ErrDDReaderTooManyTemporalLayers = errors.New("DependencyDescriptorReader: too many temporal layers")
ErrDDReaderTooManySpatialLayers = errors.New("DependencyDescriptorReader: too many spatial layers")
ErrDDReaderInvalidTemplateIndex = errors.New("DependencyDescriptorReader: invalid template index")
ErrDDReaderInvalidSpatialLayer = errors.New("DependencyDescriptorReader: invalid spatial layer, should be less than the number of resolutions")
ErrDDReaderNumDTIMismatch = errors.New("DependencyDescriptorReader: decode target indications length mismatch with structure num decode targets")
ErrDDReaderNumChainDiffsMismatch = errors.New("DependencyDescriptorReader: chain diffs length mismatch with structure num chains")
)
type DependencyDescriptorReader struct {
// Output.
descriptor *DependencyDescriptor
// Values that are needed while reading the descriptor, but can be discarded
// when reading is complete.
buffer *BitStreamReader
frameDependencyTemplateId int
activeDecodeTargetsPresentFlag bool
customDtisFlag bool
customFdiffsFlag bool
customChainsFlag bool
structure *FrameDependencyStructure
}View on GitHub (pinned to ee45c3f0b1)
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
Example fix
// before
res, err := parseDD(payload)
if err != nil { return err }
// after
res, err := parseDD(payload)
if err == dd.ErrDDReaderInvalidSpatialLayer {
// stale structure; wait for next keyframe/structure
return nil
} else if err != nil { return err } Defensive patterns
Strategy: validation
Validate before calling
func validSpatialLayer(dd *dd.DependencyDescriptor, structure *dd.Structure) bool {
return structure != nil && int(dd.FrameDependencies.SpatialId) < len(structure.Resolutions)
} Type guard
func isDDInvalidSpatialLayer(err error) bool {
return errors.Is(err, dd.ErrDDReaderInvalidSpatialLayer)
} Try / catch
if _, err := reader.Parse(buf); err != nil {
if errors.Is(err, dd.ErrDDReaderInvalidSpatialLayer) {
return nil // stale structure; skip until re-sync
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- DependencyDescriptorReader: invalid template index
- DependencyDescriptorReader: decode target indications length
- DependencyDescriptorReader: chain diffs length mismatch with
- cannot start on rtx packet
- padding only packet
AI-assisted analysis of livekit/livekit@ee45c3f0b1 (2026-09-02).
Data as JSON: /api/errors/0dbf3d04e0055ffe.
Report an issue: GitHub.