{"record":{"id":"fd2dd670c5ac1f41","repo":"AlexxIT/go2rtc","slug":"start-from-wrong-mode-c-mode-string","errorCode":null,"errorMessage":"start from wrong mode: ${c.mode.String()}","messagePattern":"start from wrong mode: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/rtsp/producer.go","lineNumber":72,"sourceCode":"\tcore.Assert(c.mode == core.ModeActiveProducer || c.mode == core.ModePassiveProducer)\n\n\tfor {\n\t\tok := false\n\n\t\tc.stateMu.Lock()\n\t\tswitch c.state {\n\t\tcase StateNone:\n\t\t\terr = nil\n\t\tcase StateConn:\n\t\t\terr = errors.New(\"start from CONN state\")\n\t\tcase StateSetup:\n\t\t\tswitch c.mode {\n\t\t\tcase core.ModeActiveProducer:\n\t\t\t\terr = c.Play()\n\t\t\tcase core.ModePassiveProducer:\n\t\t\t\terr = nil\n\t\t\tdefault:\n\t\t\t\terr = errors.New(\"start from wrong mode: \" + c.mode.String())\n\t\t\t}\n\n\t\t\tif err == nil {\n\t\t\t\tc.state = StatePlay\n\t\t\t\tok = true\n\t\t\t}\n\t\t}\n\t\tc.stateMu.Unlock()\n\n\t\tif !ok {\n\t\t\treturn\n\t\t}\n\n\t\t// Handler can return different states:\n\t\t// 1. None after PLAY should exit without error\n\t\t// 2. Play after PLAY should exit from Start with error\n\t\t// 3. Setup after PLAY should Play once again\n\t\terr = c.Handle()","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/rtsp/producer.go#L54-L90","documentation":"Inside Start(), when the Conn is in StateSetup it checks c.mode before sending PLAY. Only ModeActiveProducer (client PLAY) and ModePassiveProducer (nothing to do) are valid for a starting producer; any other mode is a programmer/lifecycle error, and the error includes the actual mode name via c.mode.String(). Start() even asserts this precondition at the top (core.Assert), so hitting this error means the assert was bypassed or mode changed after construction.","triggerScenarios":"Calling Start() on a Conn in StateSetup whose mode is neither ModeActiveProducer nor ModePassiveProducer — e.g. ModePassiveConsumer or ModeActiveConsumer connections driven through the producer Start path; or c.mode mutated after the Conn was created.","commonSituations":"Generic streaming code that calls Start() on both consumer and producer Conns without branching; a Conn built as a consumer (backchannel/pulling side) but fed into a producer pipeline; copy-pasted server-side code that reused the producer Start on a consumer Conn.","solutions":["Only call Start() on producer-mode Conns (ModeActiveProducer or ModePassiveProducer); use the consumer API path for consumer Conns.","Check c.mode before calling Start and branch to the correct start/play method for that mode.","Fix Conn construction so the mode matches the intended role; do not mutate mode after setup."],"exampleFix":"// before\nerr := conn.Start() // works only for producer modes\n// after\nif conn.Mode == core.ModeActiveProducer || conn.Mode == core.ModePassiveProducer {\n    err := conn.Start()\n} else {\n    // consumer path: use consumer start API instead\n}","handlingStrategy":"validation","validationCode":"if conn.Mode != core.ModeActiveProducer && conn.Mode != core.ModePassiveProducer {\n    return fmt.Errorf(\"Start requires producer mode, got %s\", conn.Mode.String())\n}","typeGuard":"func isProducerMode(mode core.Mode) bool {\n    return mode == core.ModeActiveProducer || mode == core.ModePassiveProducer\n}","tryCatchPattern":"if err := conn.Start(); err != nil {\n    if strings.Contains(err.Error(), \"start from wrong mode\") {\n        // route to the consumer start path for this Conn\n    }\n}","preventionTips":["Separate consumer and producer code paths; never share Start() across both.","Assert the mode right after Conn creation and fail early.","Avoid mutating c.mode after setup; make it effectively immutable.","Document expected mode per public method in doc comments."],"tags":["rtsp","invalid-state","api-misuse","state-machine"],"backgroundTag":"invalid-state-transition","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}