Skip to content

grpc@1.8.0 -- cannot read property 'name' of null #133

Description

@ntindall

We are seeing this error with grpc@1.8.0. It looks like arguejs may have some difficulty resolving the argument order inside makeUnaryRequest.

"TypeError: Cannot read property 'name' of null
    at (/srv/www/link/releases/20171219165514/node_modules/plaid-escalate client/node_modules/grpc/node_modules/arguejs/argue.js:117:46)
    at ServiceClient.Client.makeUnaryRequest (/srv/www/link/releases/20171219165514/node_modules/plaid-escalate-client/node_modules/grpc/src/client.js:507:14)
    at apply (/srv/www/link/releases/20171219165514/node_modules/plaid-escalate-client/node_modules/grpc/node_modules/lodash/lodash.js:499:17)
    at ServiceClient.wrapper (/srv/www/link/releases/20171219165514/node_modules/plaid-escalate-client/node_modules/grpc/node_modules/lodash/lodash.js:5356:16)

It seems like this is a known issue with arguejs: zvictor/ArgueJS#23.
The "bug" is just that it does an invalid dereference before it can throw a more useful error. If you change the problem line there to print out "foobar" instead of throwing a NPE, we end up with something like this:

"Error: Incompatible type signature. Expecting ( String, Function, Function, foobar, [Metadata], [Object], Function ), given ( String, Function, Function, Object, Object, Object, Function )

It seems like this is still an "irrecoverable error" type scenario, though.

here is how we are creating the client (typescript)

const root = new $protobufjs.Root();
root.resolvePath = (origin, target) =>
  path.resolve(PATH_TO_PROTO) + '/' + target;
root.loadSync(GRPC_SERVICE_DEFINITION', {
  keepCase: true,
});

const proto = grpc.loadObject(root, {
  enumsAsStrings: false,
  protobufjsVersion: 6,
});

We implement a custom promisification wrapper around the grpc prototype... at the end of the day it looks something like:

function grpcUnaryPromisifier(func: grpc.Request): any {
  // tslint:disable-next-line only-arrow-functions
  return async function promisified(
    // The argument to use
    argument: any,

    // The grpc metadata object, if undefined -- grpc will default to creation
    // of new metadata.
    metadata?: grpc.Metadata,

    // Options for this rpc
    options: grpc.CallOptions = ({} as grpc.CallOptions),
  ): P<any> {
    if (metadata == null) {
      metadata = new grpc.Metadata();
    }

    // tslint:disable no-invalid-this
    const self: EscalateClientInternal = this;
    // tslint:enable no-invalid-this

    // Populate default values into the options.
    options = R.merge({
      deadline: Date.now() + DEFAULT_TIMEOUT_MS,
    }, options);

    // do some logging, retry with exponential backoff, etc.
    try {
      const result = await P.fromCallback(cb => func.call(
            self, argument, metadata, options, cb));
    } catch (e) {
      // log and retthrow
    }

   // return the result
}

This all works fine and dandy with the client using 1.7.3...

     const metadata = new grpc.Metadata();

     if (typeof context.requestId === 'string') {
       metadata.set('request_id', context.requestId);
     }

     plaidGrpcService.client()
     .nameOfPromisifiedMethodAsync(requestObject, metadata, {
       deadline: plaidGrpcService.defaultDeadline(),
     })
     .then(res => {
       // business logic.
     })

I initially thought that there was some problem because the calling service was using grpc@1.8.0 despite the client using grpc@1.7.3. Since npm does not flatten dependencies, this should be a valid use case.

The problem first arose when we were passing a grpc.Metadata that was created by 1.8.0 to this client implementation using 1.7.3. To test whether this is the problem, I tried changing both the calling service and the client to use grpc@1.8.0 and this issue persists. With both the service and the client using 1.7.3, there is no issue. I have not tested what happens when the client uses 1.8.0 and the service uses 1.7.3.

Based upon the error I was able to coerce out of arguejs, it looks as if it is not recognizing that the Object passed in is actually a Metadata. Why this would be, I am not sure. Note that the version of arguejs that grpc uses is constant between 1.7.3 and 1.8.0.

I looked at the diff between v1.7.3 and v1.8.0 and it seems fairly innocuous, so I am rather at a loss here.

Help would be appreciated.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions