{"record":{"id":"92f0841dc8899bcd","repo":"pulumi/pulumi","slug":"analyzer-has-not-had-handshake-called","errorCode":null,"errorMessage":"analyzer has not had handshake called","messagePattern":"analyzer has not had handshake called","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdk/go/pulumi/policyx/server.go","lineNumber":277,"sourceCode":"\t\t\tEnforcementLevel: pulumirpc.EnforcementLevel(p.EnforcementLevel()),\n\t\t\tConfigSchema:     configSchema,\n\t\t})\n\t}\n\treturn &pulumirpc.AnalyzerInfo{\n\t\tName:           srv.policyPack.Name(),\n\t\tVersion:        srv.policyPack.Version().String(),\n\t\tPolicies:       policies,\n\t\tSupportsConfig: true,\n\t\tInitialConfig:  nil, /* TODO */\n\t}, nil\n}\n\nfunc (srv *analyzerServer) ConfigureStack(ctx context.Context,\n\treq *pulumirpc.AnalyzerStackConfigureRequest) (\n\t*pulumirpc.AnalyzerStackConfigureResponse, error,\n) {\n\tif srv.handshake == nil {\n\t\treturn nil, errors.New(\"analyzer has not had handshake called\")\n\t}\n\n\troot := \"\"\n\tif srv.handshake.RootDirectory != nil {\n\t\troot = *srv.handshake.RootDirectory\n\t}\n\n\tinfo := pulumi.RunInfo{\n\t\tStack:        req.Stack,\n\t\tProject:      req.Project,\n\t\tOrganization: req.Organization,\n\n\t\tRootDirectory: root,\n\n\t\tMonitorAddr: \"\",\n\t\tEngineAddr:  srv.handshake.EngineAddress,\n\n\t\tConfig:           req.Config,","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/go/pulumi/policyx/server.go#L259-L295","documentation":"The analyzer gRPC server requires that the Handshake RPC be called before any other RPC so it can learn the engine address and root directory. ConfigureStack is called before the handshake state is stored (srv.handshake == nil), meaning the engine and the analyzer plugin are speaking out of order or a non-Pulumi caller invoked the RPC directly. The library throws this to fail fast rather than constructing a context with a missing EngineAddress.","triggerScenarios":"Calling AnalyzerStackConfigure (ConfigureStack) on analyzerServer before Handshake has populated srv.handshake — e.g. a custom driver invoking RPCs in the wrong order, an outdated engine that does not send Handshake first, or a hand-rolled gRPC client/test that skips Handshake.","commonSituations":"Running an older `pulumi` CLI against a newer policy pack SDK that requires handshake; writing integration tests that call ConfigureStack directly; proxying or replaying analyzer RPC traffic out of order.","solutions":["Upgrade the Pulumi CLI/engine so Handshake is always sent before AnalyzerStackConfigure","If you invoke the analyzer server yourself, call Handshake first and pass its result (EngineAddress, RootDirectory) before ConfigureStack","In tests, construct the analyzer via analyzerServe/handshake flow instead of calling srv.ConfigureStack directly"],"exampleFix":"// before\nsrv.ConfigureStack(ctx, req) // srv.handshake == nil\n// after\nhs, err := srv.Handshake(ctx, &pulumirpc.AnalyzerHandshakeRequest{EngineAddress: engineAddr})\nif err != nil { return err }\n// now ConfigureStack can proceed\nsrv.ConfigureStack(ctx, req)","handlingStrategy":"validation","validationCode":"// when driving the analyzer directly\nif srvHandshake == nil {\n    return fmt.Errorf(\"call Handshake before ConfigureStack\")\n}\n_ = srv.ConfigureStack(ctx, req)","typeGuard":"func handshakeDone(h *pulumirpc.AnalyzerHandshakeRequest) bool { return h != nil }","tryCatchPattern":"if err := srv.ConfigureStack(ctx, req); err != nil {\n    if strings.Contains(err.Error(), \"has not had handshake called\") {\n        // re-run Handshake then retry\n    }\n}","preventionTips":["Always run the analyzer through AnalyzerMain/RunAnalyzer so the RPC order is managed for you","In custom drivers, invoke Handshake first, unconditionally","Pin the CLI version your policy pack supports"],"tags":["go","grpc","policy","lifecycle-order"],"backgroundTag":"rpc-called-before-handshake","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}