grpc-web icon indicating copy to clipboard operation
grpc-web copied to clipboard

TypeError: b is not a function. (In 'b(null, d)', 'b' is undefined)

Open christopher-wong opened this issue 4 years ago • 7 comments

Hi there,

I'm having some issues invoking gRPC-web calls from my React application. Invoking my RPC works correctly and the server receives the request without issue, however an error appears in my console on every request.

index.js:60 Uncaught TypeError: b is not a function
    at Array.<anonymous> (index.js:60)
    at yc (index.js:53)
    at S.<anonymous> (index.js:51)
    at Ib (index.js:34)
    at O (index.js:33)
    at oc (index.js:42)
    at S.push../node_modules/grpc-web/index.js.S.O (index.js:40)
    at S.push../node_modules/grpc-web/index.js.S.K (index.js:40)

I'm running a gRPC server in Go with a React application communicating with the Go server via the Envoy proxy.

I compile my Proto using the following command:

protoc \
		--js_out=import_style=commonjs,binary:web-client/src/ \
		--grpc-web_out=import_style=commonjs,mode=grpcwebtext:web-client/src/ \
		proto/myapp.proto
$ protoc --version
libprotoc 3.14.0

and I build my request from React like so:

const { GetMessagesRequest, Message } = require('../../proto/myapp_pb.js');
const { MyappClient } = require('../../proto/myapp_grpc_web_pb');

const myappService = new MyappClient('http://localhost:8080');
const msg = new Message()

const meta = {
    "authorization": "fake_123456",
  }

await myappService.broadcast(msg, meta)

christopher-wong avatar Feb 19 '21 03:02 christopher-wong

Similar issue, protoc 3.13.0, same compile command.

index.js:60 Uncaught TypeError: b is not a function
    at Array.<anonymous> (index.js:60)
    at X (index.js:53)
    at S.<anonymous> (index.js:51)
    at Ib (index.js:34)
    at O (index.js:33)
    at oc (index.js:42)
    at S.push../node_modules/grpc-web/index.js.S.O (index.js:40)
    at S.push../node_modules/grpc-web/index.js.S.K (index.js:40)

alertedsnake avatar Feb 25 '21 06:02 alertedsnake

I can confirm that with 1.1.0 this problem does not exist, so it was introduced in the 1.2.0 release.

alertedsnake avatar Feb 25 '21 06:02 alertedsnake

My coworker found the issue here - before, my call looked like this:

function doCall() {
  return new Promise((resolve, reject) => {
        client.rpcCall(request)
            .on("data", () => resolve())
            .on("status", () => {})
            .on("error", response => reject(response.message));
   });
}

But now it needs to look like:

function doCall() {
  return new Promise((resolve, reject) => {
        client.rpcCall(request, null, (err, response) => {
            if (err) {
                reject(err.message);
            }
            else {
                resolve();
            }
        });
   });
}

Hopefully this may help you as well.

alertedsnake avatar Feb 25 '21 23:02 alertedsnake

I'm getting the same error with 1.3.0

jackzzj avatar Jan 26 '22 01:01 jackzzj

Hi! Thanks for the bug report and sorry for the delay!

I'm curious if this bug is specific to the Go grpc server, or this is more common than that?

I'm not quite able to reproduce this issue on the nodejs + commonjs example that we have here. So i will need some help to reproduce.. :)

If someone could create a minimal repro in Docker maybe i could try it out and debug it.

Thanks! :)

sampajano avatar Jan 28 '22 01:01 sampajano

Thanks a lot for that piece of code @alertedsnake there are some similar syntax for a server stream?

I want to isolate the protobuf code from my component so I want to process each batch of the stream separately


import {ResultServiceClient} from "../protobuf/generated/result_grpc_web_pb";

const resultMessages = require('../protobuf/generated/result_pb')

export class ResultService {
    client: ResultServiceClient
    messages: any
    stream: any

    constructor() {
        this.client = new ResultServiceClient("http://localhost:8080", null, null)
        this.messages = resultMessages
    }

    getStream(batchUuid: string) {
        let streamResultsRequest = new resultMessages.StreamResultsRequest()
        streamResultsRequest.setBatchUuid(batchUuid)
        this.stream = this.client.streamResults(streamResultsRequest, {})
    }

    // something like this but get each batch as a promise not only the first one or all together
    getData() {
        return new Promise((resolve, reject) => {
            this.stream.on('data', function (response: { getResultsList: () => any; }) {
                resolve(response.getResultsList())
            });
        })
    }
}

Enrikerf avatar Mar 08 '22 18:03 Enrikerf

@Enrikerf oh - I'm FAR from the right person to be asking, I do very little Javascript, not sure I can really help much :)

alertedsnake avatar Mar 08 '22 18:03 alertedsnake