Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uncaught exception from ProxyChannel.fromService #192365

Closed
mroch opened this issue Sep 7, 2023 · 3 comments
Closed

uncaught exception from ProxyChannel.fromService #192365

mroch opened this issue Sep 7, 2023 · 3 comments
Assignees
Labels
debt Code quality issues insiders-released Patch has been released in VS Code Insiders

Comments

@mroch
Copy link
Contributor

mroch commented Sep 7, 2023

this code requires that IServerChannel.call returns a promise:

try {
promise = channel.call(this.ctx, request.name, request.arg, cancellationTokenSource.token);
} catch (err) {
promise = Promise.reject(err);
}
const id = request.id;
promise.then(data => {

otherwise, the then() call fails. in the example below, it returns undefined, which does not have a .then property.

but ProxyChannel.fromService is unsound. it is typed to return a Promise, but if target() doesn't return a promise then its return type is a lie:

call(_: unknown, command: string, args?: any[]): Promise<any> {
const target = handler[command];
if (typeof target === 'function') {
// Revive unless marshalling disabled
if (!disableMarshalling && Array.isArray(args)) {
for (let i = 0; i < args.length; i++) {
args[i] = revive(args[i]);
}
}
return target.apply(handler, args);
}
throw new ErrorNoTelemetry(`Method not found: ${command}`);
}

this ProxyChannel.fromService is a problem:

// Custom Endpoint Telemetry
const customEndpointTelemetryChannel = ProxyChannel.fromService(accessor.get(ICustomEndpointTelemetryService));
this.server.registerChannel('customEndpointTelemetry', customEndpointTelemetryChannel);

because it has methods that don't return promises:

publicLog(endpoint: ITelemetryEndpoint, eventName: string, data?: ITelemetryData): void;
publicLogError(endpoint: ITelemetryEndpoint, errorEventName: string, data?: ITelemetryData): void;

this leads to, in my case at least, an uncaught exception in sharedProcess.

I added this in ipc.ts and it logged this while debugging extensions:

if (!promise) {
  throw new Error(`Call returned undefined: ${request.channelName}.${request.name}(${request.arg})`);
}

Call returned undefined: customEndpointTelemetry.publicLog([object Object],js-debug/launch,[object Object])

@mroch mroch changed the title uncaught exception from ProxyChannel.fromService` uncaught exception from ProxyChannel.fromService Sep 7, 2023
@billti
Copy link
Member

billti commented Sep 22, 2023

I've just spent quite a while debugging my own trivial extension and why it was failing to launch under the debugger to arrive at exactly this issue. Below is the call stack and some custom logging I added at the start when promise is undefined. It matches the above analysis.

Promise is:  undefined
channel is:  {}
request.channel name is: customEndpointTelemetry
ctx is:  window:1
request name is  publicLog
  ERR [uncaught exception in sharedProcess]: Cannot read properties of undefined (reading 'then'): TypeError: Cannot read properties of undefined (reading 'then')
    at ChannelServer.onPromise (/Users/billti/src/vscode/out/vs/base/parts/ipc/common/ipc.js:301:21)
    at ChannelServer.onRawMessage (/Users/billti/src/vscode/out/vs/base/parts/ipc/common/ipc.js:266:33)
    at UniqueContainer.value (/Users/billti/src/vscode/out/vs/base/parts/ipc/common/ipc.js:217:73)
    at Emitter._deliver (/Users/billti/src/vscode/out/vs/base/common/event.js:891:26)
    at Emitter._deliverQueue (/Users/billti/src/vscode/out/vs/base/common/event.js:902:22)
    at Emitter.fire (/Users/billti/src/vscode/out/vs/base/common/event.js:925:22)
    at MessagePortMain.fn (/Users/billti/src/vscode/out/vs/base/common/event.js:455:44)
    at MessagePortMain.emit (node:events:513:28)
    at MessagePortMain._internalPort.emit (node:electron/js2c/utility_init:2:367)
    at Object.callbackTrampoline (node:internal/async_hooks:130:17)

@billti
Copy link
Member

billti commented Sep 23, 2023

Note: Turns out the extension was failing for a different reason, but this error led me on a wild goose chase for quite a few hours thinking it was the problem, so would be good to fix :)

@chrmarti chrmarti assigned joaomoreno and unassigned chrmarti Sep 26, 2023
@joaomoreno joaomoreno assigned bpasero and unassigned joaomoreno Sep 26, 2023
@bpasero
Copy link
Member

bpasero commented Sep 26, 2023

@mroch @billti good findings, would you like to contribute a PR with a fix? Maybe here we should check on the return type and wrap into a Promise if not already one?

return target.apply(handler, args);

@bpasero bpasero added the debt Code quality issues label Sep 26, 2023
@bpasero bpasero added this to the September 2023 milestone Sep 28, 2023
@vscodenpa vscodenpa added unreleased Patch has not yet been released in VS Code Insiders insiders-released Patch has been released in VS Code Insiders and removed unreleased Patch has not yet been released in VS Code Insiders labels Sep 28, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Nov 12, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
debt Code quality issues insiders-released Patch has been released in VS Code Insiders
Projects
None yet
Development

No branches or pull requests

6 participants