{"record":{"id":"aa452786715a8278","repo":"grpc/grpc-go","slug":"manual-resolver-instance-has-not-yet-been-built","errorCode":null,"errorMessage":"Manual resolver instance has not yet been built.","messagePattern":"Manual resolver instance has not yet been built\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"resolver/manual/manual.go","lineNumber":127,"sourceCode":"// InitialState.\nfunc (r *Resolver) UpdateState(s resolver.State) {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\tr.lastSeenState = &s\n\tif r.cc == nil {\n\t\treturn\n\t}\n\terr := r.cc.UpdateState(s)\n\tr.UpdateStateCallback(err)\n}\n\n// CC returns r's ClientConn when r was last Built.  Panics if the resolver has\n// not been Built before.\nfunc (r *Resolver) CC() resolver.ClientConn {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\tif r.cc == nil {\n\t\tpanic(\"Manual resolver instance has not yet been built.\")\n\t}\n\treturn r.cc\n}\n","sourceCodeStart":109,"sourceCodeEnd":131,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/resolver/manual/manual.go#L109-L131","documentation":"The manual resolver (resolver/manual/manual.go:123) exposes CC() to get the ClientConn it was wired into. CC() panics if the resolver has not been Build() yet (r.cc == nil), because there is no connection to return. The manual resolver is primarily a testing/dialing helper; this panic signals the resolver was used before dialing.","triggerScenarios":"Calling r.CC() on a manual.Resolver before grpc.Dial has invoked the resolver's Build (i.e., before the channel actually started using it). Also calling CC() after Close() if cc was cleared.","commonSituations":"Test code grabbing r.CC() to push UpdateState before the dial completed; reordering setup so CC() is called before Dial; using a manual resolver as if it were already connected.","solutions":["Ensure grpc.Dial/ NewClient with the manual scheme has been called (and Build invoked) before calling CC().","Use UpdateState() instead of CC() for seeding initial state - UpdateState is safe before Build (it stores lastSeenState).","If you need the ClientConn, capture the one returned by grpc.Dial/ NewClient directly rather than via r.CC()."],"exampleFix":"// before\nr, _ := manual.GenerateAndRegisterManualResolver()\ncc := r.CC() // panics: not built yet\n\n// after\nr, _ := manual.GenerateAndRegisterManualResolver()\nconn, _ := grpc.NewClient(r.Scheme()+\":///unused\", grpc.WithResolvers(r))\n// now r.CC() is safe, or just use conn directly","handlingStrategy":"validation","validationCode":"// Dial before using CC(); use UpdateState for pre-build state\nr, _ := manual.GenerateAndRegisterManualResolver()\nconn, _ := grpc.NewClient(r.Scheme()+\":///unused\", grpc.WithResolvers(r))\n// Now r.CC() is safe; or simply use conn.\n// For initial state before build, prefer:\n// r.UpdateState(resolver.State{...}) // safe pre-build","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always call grpc.Dial/ NewClient before invoking CC() on a manual resolver.","Use UpdateState() (not CC()) to seed initial resolver state - it is safe before Build.","Capture the ClientConn returned by Dial directly rather than round-tripping through r.CC()."],"tags":["resolver","manual","panic","grpc-go","testing"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}