{"record":{"id":"41fb3653c1fe7e4e","repo":"ToolJet/ToolJet","slug":"service-servicename-is-not-a-valid-constructor","errorCode":null,"errorMessage":"Service ${serviceName} is not a valid constructor function","messagePattern":"Service (.+?) is not a valid constructor function","errorType":"exception","errorClass":"GrpcOperationError","httpStatus":null,"severity":"error","filePath":"plugins/packages/grpcv2/lib/operations.ts","lineNumber":91,"sourceCode":"    if (!descriptor) {\n      throw new GrpcOperationError(`Service descriptor not found for ${serviceName}`);\n    }\n\n    const packageObject = descriptor.getPackageObject({\n      keepCase: true,\n      enums: String,\n      longs: String,\n      defaults: true,\n      oneofs: true\n    });\n\n    const service = findServiceInPackage(packageObject, serviceName);\n    if (!service) {\n      throw new GrpcOperationError(`Service ${serviceName} not found in proto descriptor`);\n    }\n\n    if (typeof service !== 'function') {\n      throw new GrpcOperationError(`Service ${serviceName} is not a valid constructor function`);\n    }\n\n    const credentials = buildChannelCredentials(sourceOptions);\n    const cleanUrl = sanitizeGrpcServerUrl(sourceOptions.url, sourceOptions.ssl_enabled);\n    const ServiceConstructor = service as new (url: string, credentials: any) => GrpcClient;\n    const grpcClient = new ServiceConstructor(cleanUrl, credentials);\n\n    return grpcClient;\n  } catch (error: unknown) {\n    const err = toError(error);\n    throw new GrpcOperationError(`Failed to create reflection client for service ${serviceName}: ${err.message}`, error);\n  }\n};\n\nexport const buildProtoFileClient = async (sourceOptions: SourceOptions, serviceName: string): Promise<GrpcClient> => {\n  try {\n    const packageDefinition = await loadProtoFromRemoteUrl(sourceOptions.proto_file_url!);\n    const grpcObject = grpc.loadPackageDefinition(packageDefinition);","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/ToolJet/ToolJet/blob/20602a8e101f2e59686c9afde0d1402aac2c8871/plugins/packages/grpcv2/lib/operations.ts#L73-L109","documentation":"Thrown in buildReflectionClient when findServiceInPackage returns a value but typeof service !== 'function'. A gRPC service constructor must be a function; getting a non-function (typically an object or namespace) means the resolved symbol is a nested package/namespace, not a service constructor. The traversal matched a container, not the service itself.","triggerScenarios":"serviceName resolves to a package or namespace object rather than the service constructor — e.g. the name matches a package that contains the service. A proto where a message or enum name shadows the service name.","commonSituations":"Service and package sharing a name; pointing at an intermediate namespace; descriptor version where the service symbol is wrapped differently; stale descriptor cached by reflection.","solutions":["Target the fully-qualified service symbol that resolves to the constructor, not an enclosing namespace.","Verify the proto: a service keyword defines the callable; ensure the name maps to that, not a package or message.","Retry after refreshing the reflection descriptor cache."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const isServiceConstructor = (v: unknown): v is new (url: string, creds: any) => GrpcClient =>\n  typeof v === 'function';\n// usage: if (!isServiceConstructor(sym)) throw new Error(`${name} is a namespace, not a service`);","tryCatchPattern":null,"preventionTips":["Resolve to the service symbol, not an enclosing namespace/message.","Disambiguate name collisions with full package paths.","Validate typeof === 'function' before constructing clients in your own wrappers."],"tags":["reflection","descriptor","name-resolution","proto"],"backgroundTag":null,"analyzedSha":"20602a8e101f2e59686c9afde0d1402aac2c8871","analyzedAt":"2026-08-13T05:58:54.221Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}