{"record":{"id":"884bc056c98fe1d3","repo":"temporalio/temporal","slug":"upload-stream-unknown-status-v","errorCode":null,"errorMessage":"upload stream unknown status: %v","messagePattern":"upload stream unknown status: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/replication/bi_direction_stream.go","lineNumber":153,"sourceCode":"}\n\nfunc (s *BiDirectionStreamImpl[Req, Resp]) lazyInitLocked() error {\n\tswitch s.status {\n\tcase streamStatusInitialized:\n\t\tstreamingClient, err := s.clientProvider.Get(s.ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.streamingClient = streamingClient\n\t\ts.status = streamStatusOpen\n\t\tgo s.recvLoop()\n\t\treturn nil\n\tcase streamStatusOpen:\n\t\treturn nil\n\tcase streamStatusClosed:\n\t\treturn ErrClosed\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"upload stream unknown status: %v\", s.status))\n\t}\n}\n\nfunc (s *BiDirectionStreamImpl[Req, Resp]) recvLoop() {\n\tdefer close(s.channel)\n\tdefer s.Close()\n\n\tfor {\n\t\tresp, err := s.streamingClient.Recv()\n\t\tswitch err {\n\t\tcase nil:\n\t\t\ts.notifyRecvChannel(resp, nil)\n\t\tcase io.EOF:\n\t\t\treturn\n\t\tdefault:\n\t\t\tvar errResp Resp\n\t\t\ts.notifyRecvChannel(errResp, NewStreamError(\"BiDirectionStream recv error\", err))\n\t\t\treturn","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/replication/bi_direction_stream.go#L135-L171","documentation":"BiDirectionStreamImpl manages a replication stream with an internal status (created/open/closed). lazyInitLocked converts the current status into an action: open returns the stream, closed returns ErrClosed; any other status value means the status enum was extended without updating this switch, so it panics. It is a defensive default branch against unknown future states.","triggerScenarios":"A new streamStatus constant added to the package but not handled in lazyInitLocked's switch; memory corruption or a race setting s.status to an invalid value.","commonSituations":"Hit almost exclusively when developing/forking temporal-server and adding a stream state (e.g. 'initializing') without updating lazyInitLocked; extremely rare in production builds.","solutions":["Add the missing status case to the switch in lazyInitLocked with appropriate handling","Grep for all streamStatus* constants and confirm every one is handled in the status switches","If hit on an unmodified build, check for data races on BiDirectionStreamImpl (run with -race)"],"exampleFix":"// before\ncase streamStatusClosed:\n  return ErrClosed\ndefault:\n  panic(fmt.Sprintf(\"upload stream unknown status: %v\", s.status))\n// after\ncase streamStatusClosed:\n  return ErrClosed\ncase streamStatusInitializing: // newly added state\n  return nil\ndefault:\n  panic(fmt.Sprintf(\"upload stream unknown status: %v\", s.status))","handlingStrategy":"validation","validationCode":"// When adding a stream status, verify all switches handle it:\n// grep -rn \"streamStatus\" service/history/replication/ | grep -v _test\n// ensure each switch on s.status includes the new constant","typeGuard":"func streamStatusKnown(s streamStatus) bool {\n  switch s {\n  case streamStatusCreated, streamStatusOpen, streamStatusClosed:\n    return true\n  }\n  return false\n}","tryCatchPattern":"// Panic path; wrap stream initialization:\nfunc safeLazyInit(s *replication.BiDirectionStream[Req, Resp]) (err error) {\n  defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"stream status panic: %v\", r) } }()\n  return s.EnsureOpen()\n}","preventionTips":["Handle every streamStatus constant in every switch over s.status","When adding a stream state, update lazyInitLocked and recvLoop/sendLoop switches together","Run replication tests with -race when touching stream state transitions"],"tags":["go","replication","streaming","unhandled-enum-case"],"backgroundTag":"unknown-enum-state","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}