@@ -59,6 +59,7 @@ import { mainWindow } from '../../../../base/browser/window.js';
5959import { IOpenerService } from '../../../../platform/opener/common/opener.js' ;
6060import { URI } from '../../../../base/common/uri.js' ;
6161import { IHostService } from '../../../services/host/browser/host.js' ;
62+ import Severity from '../../../../base/common/severity.js' ;
6263
6364const defaultChat = {
6465 extensionId : product . defaultChatAgent ?. extensionId ?? '' ,
@@ -365,6 +366,8 @@ class ChatSetupRequests extends Disposable {
365366 @ILogService private readonly logService : ILogService ,
366367 @IRequestService private readonly requestService : IRequestService ,
367368 @IChatQuotasService private readonly chatQuotasService : IChatQuotasService ,
369+ @IDialogService private readonly dialogService : IDialogService ,
370+ @IOpenerService private readonly openerService : IOpenerService
368371 ) {
369372 super ( ) ;
370373
@@ -486,7 +489,12 @@ class ChatSetupRequests extends Disposable {
486489 return { entitlement : ChatEntitlement . Unresolved } ;
487490 }
488491
489- const responseText = await asText ( response ) ;
492+ let responseText : string | null = null ;
493+ try {
494+ responseText = await asText ( response ) ;
495+ } catch ( error ) {
496+ // ignore - handled below
497+ }
490498 if ( token . isCancellationRequested ) {
491499 return undefined ;
492500 }
@@ -589,18 +597,38 @@ class ChatSetupRequests extends Disposable {
589597
590598 const response = await this . request ( defaultChat . entitlementSignupLimitedUrl , 'POST' , body , session , CancellationToken . None ) ;
591599 if ( ! response ) {
592- this . logService . error ( '[chat setup] sign-up: no response' ) ;
600+ this . onUnknownSignUpError ( '[chat setup] sign-up: no response' ) ;
593601 return false ;
594602 }
595603
596604 if ( response . res . statusCode && response . res . statusCode !== 200 ) {
597- this . logService . error ( `[chat setup] sign-up: unexpected status code ${ response . res . statusCode } ` ) ;
605+ if ( response . res . statusCode === 422 ) {
606+ try {
607+ const responseText = await asText ( response ) ;
608+ if ( responseText ) {
609+ const responseError : { message : string } = JSON . parse ( responseText ) ;
610+ if ( typeof responseError . message === 'string' && responseError . message ) {
611+ this . onUnprocessableSignUpError ( `[chat setup] sign-up: unprocessable entity (${ responseError . message } )` , responseError . message ) ;
612+ return false ;
613+ }
614+ }
615+ } catch ( error ) {
616+ // ignore - handled below
617+ }
618+ }
619+ this . onUnknownSignUpError ( `[chat setup] sign-up: unexpected status code ${ response . res . statusCode } ` ) ;
598620 return false ;
599621 }
600622
601- const responseText = await asText ( response ) ;
623+ let responseText : string | null = null ;
624+ try {
625+ responseText = await asText ( response ) ;
626+ } catch ( error ) {
627+ // ignore - handled below
628+ }
629+
602630 if ( ! responseText ) {
603- this . logService . error ( '[chat setup] sign-up: response has no content' ) ;
631+ this . onUnknownSignUpError ( '[chat setup] sign-up: response has no content' ) ;
604632 return false ;
605633 }
606634
@@ -609,7 +637,7 @@ class ChatSetupRequests extends Disposable {
609637 parsedResult = JSON . parse ( responseText ) ;
610638 this . logService . trace ( `[chat setup] sign-up: response is ${ responseText } ` ) ;
611639 } catch ( err ) {
612- this . logService . error ( `[chat setup] sign-up: error parsing response (${ err } )` ) ;
640+ this . onUnknownSignUpError ( `[chat setup] sign-up: error parsing response (${ err } )` ) ;
613641 }
614642
615643 const subscribed = Boolean ( parsedResult ?. subscribed ) ;
@@ -626,6 +654,30 @@ class ChatSetupRequests extends Disposable {
626654 return subscribed ;
627655 }
628656
657+ private onUnknownSignUpError ( logMessage : string ) : void {
658+ this . dialogService . error ( localize ( 'unknownSignUpError' , "An error occurred while signing up for Copilot Free." ) , localize ( 'unknownSignUpErrorDetail' , "Please try again." ) ) ;
659+ this . logService . error ( logMessage ) ;
660+ }
661+
662+ private onUnprocessableSignUpError ( logMessage : string , logDetails : string ) : void {
663+ this . dialogService . prompt ( {
664+ type : Severity . Error ,
665+ message : localize ( 'unprocessableSignUpError' , "An error occurred while signing up for Copilot Free." ) ,
666+ detail : logDetails ,
667+ buttons : [
668+ {
669+ label : localize ( 'ok' , "OK" ) ,
670+ run : ( ) => { /* noop */ }
671+ } ,
672+ {
673+ label : localize ( 'learnMore' , "Learn More" ) ,
674+ run : ( ) => this . openerService . open ( URI . parse ( defaultChat . upgradePlanUrl ) )
675+ }
676+ ] ,
677+ } ) ;
678+ this . logService . error ( logMessage ) ;
679+ }
680+
629681 override dispose ( ) : void {
630682 this . pendingResolveCts . dispose ( true ) ;
631683
@@ -644,7 +696,7 @@ type InstallChatClassification = {
644696 signedIn : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'Whether the user did sign in prior to installing the extension.' } ;
645697} ;
646698type InstallChatEvent = {
647- installResult : 'installed' | 'cancelled' | 'failedInstall' | 'failedNotSignedIn' ;
699+ installResult : 'installed' | 'cancelled' | 'failedInstall' | 'failedNotSignedIn' | 'failedSignUp' ;
648700 signedIn : boolean ;
649701} ;
650702
@@ -790,6 +842,10 @@ class ChatSetupController extends Disposable {
790842
791843 if ( entitlement !== ChatEntitlement . Limited && entitlement !== ChatEntitlement . Pro && entitlement !== ChatEntitlement . Unavailable ) {
792844 didSignUp = await this . requests . signUpLimited ( session ) ;
845+
846+ if ( ! didSignUp ) {
847+ this . telemetryService . publicLog2 < InstallChatEvent , InstallChatClassification > ( 'commandCenter.chatInstall' , { installResult : 'failedSignUp' , signedIn } ) ;
848+ }
793849 }
794850
795851 await this . extensionsWorkbenchService . install ( defaultChat . extensionId , {
0 commit comments