{"record":{"id":"c169fb853e058956","repo":"grafana/k6","slug":"can-t-convert-method-info-w","errorCode":null,"errorMessage":"can't convert method info: %w","messagePattern":"can't convert method info: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/grpc/client.go","lineNumber":285,"sourceCode":"\tc.addr = addr\n\tc.conn, err = grpcext.Dial(ctx, addr, c.types, opts...)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif !p.UseReflectionProtocol {\n\t\treturn true, nil\n\t}\n\n\tctx = metadata.NewOutgoingContext(ctx, p.ReflectionMetadata)\n\n\tfdset, err := c.conn.Reflect(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\t_, err = c.convertToMethodInfo(fdset)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"can't convert method info: %w\", err)\n\t}\n\n\treturn true, err\n}\n\n// HealthCheck checks if the server side is up and ready to serve responses\nfunc (c *Client) HealthCheck(svc *string) (*grpcext.HealthCheckResponse, error) {\n\tvar service string\n\tif svc != nil {\n\t\tservice = *svc\n\t}\n\treturn c.conn.HealthCheck(c.vu.Context(), service)\n}\n\n// Invoke creates and calls a unary RPC by fully qualified method name\nfunc (c *Client) Invoke(\n\tmethod string,\n\treq sobek.Value,","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/grpc/client.go#L267-L303","documentation":"After a successful server reflection handshake (connect with reflect: true), k6 converts the returned FileDescriptorSet into method/type descriptors; if protodesc.NewFiles rejects the descriptors (invalid or incomplete, e.g. unresolved imports) or a message registration fails, the error is wrapped as 'can't convert method info' (internal/js/modules/k6/grpc/client.go:285). The gRPC connection itself worked - it is the server's advertised schema that could not be processed.","triggerScenarios":"client.connect(addr, { reflect: true }) against a server whose reflection returns descriptors with missing dependencies, or whose symbols conflict with definitions already registered by an earlier client.load() on the same client.","commonSituations":"Proxies or service meshes that implement gRPC reflection partially; servers whose runtime descriptors omit transitive imports; mixing client.load() and reflect: true on the same client instance.","solutions":["Fall back to a locally compiled protoset with client.load() instead of reflection","Upgrade k6 - descriptor conversion handling has improved across releases","If you own the server, ensure reflection serves complete descriptors (all imports); otherwise report the incompatibility with server and k6 versions"],"exampleFix":"// before\nclient.connect(addr, { reflect: true });\n\n// after - fall back to a local protoset\nclient.load('./pb/service.protoset');\nclient.connect(addr, {});","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"client.connect(addr, { reflect: true }).catch?.(() => {}) ?? null;\ntry {\n  client.connect(addr, { reflect: true });\n} catch (e) {\n  if (/can't convert method info/.test(e.message)) {\n    client.load('./pb/service.protoset'); // fallback: local descriptors\n    client.connect(addr, {});\n  } else throw e;\n}","preventionTips":["Keep a compiled protoset next to the script as a reflection fallback","Don't mix client.load() and reflect: true for the same services on one client","Pin known-good k6/server version pairs in CI"],"tags":["grpc","k6","reflection","protobuf","descriptors"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}