{"record":{"id":"4d4bb25affe114d7","repo":"pion/webrtc","slug":"cannot-add-ogg-tracks-after-writing-has-started","errorCode":null,"errorMessage":"cannot add Ogg tracks after writing has started","messagePattern":"cannot add Ogg tracks after writing has started","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/media/oggwriter/oggwriter.go","lineNumber":53,"sourceCode":"\tchannelMappingFamily2              = 2\n\tchannelMappingFamily255            = 255\n\tidPageSignature                    = \"OpusHead\"\n\tcommentPageSignature               = \"OpusTags\"\n\tdefaultVendor                      = \"pion\"\n\tpageHeaderSignature                = \"OggS\"\n\tpageHeaderSize                     = 27\n\tmaxOggPageSegments                 = 255\n\tnoGranulePosition                  = ^uint64(0)\n\tmaxUint32Length                    = uint64(1<<32 - 1)\n)\n\nvar (\n\terrFileNotOpened        = errors.New(\"file not opened\")\n\terrOutputNotOpened      = errors.New(\"output not opened\")\n\terrInvalidNilPacket     = errors.New(\"invalid nil packet\")\n\terrDuplicateTrackSSRC   = errors.New(\"duplicate Ogg track SSRC\")\n\terrDuplicateTrackSerial = errors.New(\"duplicate Ogg track serial\")\n\terrTracksStarted        = errors.New(\"cannot add Ogg tracks after writing has started\")\n\terrPacketSSRCMismatch   = errors.New(\"RTP packet SSRC does not match Ogg track SSRC\")\n\terrInvalidOpusPacket    = errors.New(\"invalid Opus packet\")\n\terrInvalidChannelCount  = errors.New(\"invalid channel count\")\n\terrInvalidChannelMap    = errors.New(\"invalid channel mapping\")\n\terrInvalidOpusTags      = errors.New(\"invalid OpusTags\")\n)\n\ntype pageRewriter interface {\n\tio.Seeker\n\tio.WriterAt\n}\n\ntype writerConfig struct {\n\tsampleRate     uint32\n\tchannelMapping channelMapping\n\tpageRewriter   pageRewriter\n\topusTags       OpusTags\n}","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/pion/webrtc/blob/8c25dc09fa9e7c09aac4309ead88093d760432b0/pkg/media/oggwriter/oggwriter.go#L35-L71","documentation":"errTracksStarted is returned by NewTrack when an attempt is made to add a track after the writer has begun writing Ogg pages (w.started is true). Ogg stream headers must be written before any data pages, so late tracks cannot be interleaved into an in-progress file. It is a lifecycle/state error of the writer.","triggerScenarios":"Calling writer.NewTrack(...) after any packet write has started the writer — e.g. after track.WriteRTP has flushed headers and data pages, then calling NewTrack again.","commonSituations":"Dynamically adding audio tracks mid-recording; a code path that adds a fallback/second track after writing has already begun; tests asserting the writer rejects late tracks.","solutions":["Add all tracks before writing the first RTP packet","Create a new oggwriter instance if you need to add tracks after writing started","Restructure so track discovery/completion happens before recording begins"],"exampleFix":"// before\ntrack1, _ := writer.NewTrack(1111, nil)\n_ = track1.WriteRTP(pkt) // writer now started\ntrack2, err := writer.NewTrack(2222, nil) // errTracksStarted\n// after\ntrack1, _ := writer.NewTrack(1111, nil)\ntrack2, _ := writer.NewTrack(2222, nil)\n_ = track1.WriteRTP(pkt)","handlingStrategy":"validation","validationCode":"if writer.Started() { // or track via your own flag set after first WriteRTP\n    return errors.New(\"cannot add track after writing started\")\n}","typeGuard":null,"tryCatchPattern":"track, err := writer.NewTrack(ssrc, opts)\nif errors.Is(err, oggwriter.errTracksStarted) {\n    writer, err = newWriterAndReaddTracks() // recreate writer for late tracks\n}","preventionTips":["Create all tracks immediately after opening the writer","Never interleave NewTrack calls with WriteRTP calls","Structure the pipeline so track setup completes before the first packet","If dynamic tracks are required, open a new writer per phase"],"tags":["ogg","lifecycle","state","media"],"backgroundTag":"invalid-operation-state","analyzedSha":"8c25dc09fa9e7c09aac4309ead88093d760432b0","analyzedAt":"2026-09-03T21:56:56.182Z","contentChangedAt":"2026-09-03T21:56:56.182Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}