Skip to content

Commit db6b4ad

Browse files
committed
fix: extract clean error messages from API responses
When API requests fail with non-JSON responses (like HTML error pages), error messages now show the HTTP status code (e.g., "HTTP 521 Web Server Is Down") instead of serializing the entire response body. Added getApiErrorMessage(error, response) utility that extracts clean error messages from ODS, OCAPI, and SCAPI error patterns with HTTP status fallback.
1 parent d6056c2 commit db6b4ad

22 files changed

Lines changed: 320 additions & 53 deletions

File tree

.changeset/fix-error-output.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@salesforce/b2c-cli': patch
3+
'@salesforce/b2c-tooling-sdk': patch
4+
---
5+
6+
Fix HTML response bodies appearing in ERROR log lines. When API requests fail with non-JSON responses (like HTML error pages), error messages now show the HTTP status code (e.g., "HTTP 521 Web Server Is Down") instead of serializing the entire response body.
7+
8+
Added `getApiErrorMessage(error, response)` utility that extracts clean error messages from ODS, OCAPI, and SCAPI error patterns with HTTP status fallback.

packages/b2c-cli/src/commands/ods/create.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import {Flags, ux} from '@oclif/core';
77
import cliui from 'cliui';
88
import {OdsCommand} from '@salesforce/b2c-tooling-sdk/cli';
9-
import type {OdsComponents} from '@salesforce/b2c-tooling-sdk';
9+
import {getApiErrorMessage, type OdsComponents} from '@salesforce/b2c-tooling-sdk';
1010
import {t} from '../../i18n/index.js';
1111

1212
type SandboxModel = OdsComponents['schemas']['SandboxModel'];
@@ -139,11 +139,9 @@ export default class OdsCreate extends OdsCommand<typeof OdsCreate> {
139139
});
140140

141141
if (!result.data?.data) {
142-
const errorResponse = result.error as OdsComponents['schemas']['ErrorResponse'] | undefined;
143-
const errorMessage = errorResponse?.error?.message || result.response?.statusText || 'Unknown error';
144142
this.error(
145143
t('commands.ods.create.error', 'Failed to create sandbox: {{message}}', {
146-
message: errorMessage,
144+
message: getApiErrorMessage(result.error, result.response),
147145
}),
148146
);
149147
}

packages/b2c-cli/src/commands/ods/delete.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import * as readline from 'node:readline';
77
import {Args, Flags} from '@oclif/core';
88
import {OdsCommand} from '@salesforce/b2c-tooling-sdk/cli';
9-
import type {OdsComponents} from '@salesforce/b2c-tooling-sdk';
9+
import {getApiErrorMessage} from '@salesforce/b2c-tooling-sdk';
1010
import {t} from '../../i18n/index.js';
1111

1212
/**
@@ -92,11 +92,9 @@ export default class OdsDelete extends OdsCommand<typeof OdsDelete> {
9292
});
9393

9494
if (result.response.status !== 202) {
95-
const errorResponse = result.error as OdsComponents['schemas']['ErrorResponse'] | undefined;
96-
const errorMessage = errorResponse?.error?.message || result.response?.statusText || 'Unknown error';
9795
this.error(
9896
t('commands.ods.delete.error', 'Failed to delete sandbox: {{message}}', {
99-
message: errorMessage,
97+
message: getApiErrorMessage(result.error, result.response),
10098
}),
10199
);
102100
}

packages/b2c-cli/src/commands/ods/list.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
import {Flags} from '@oclif/core';
77
import {OdsCommand, TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli';
8-
import type {OdsComponents} from '@salesforce/b2c-tooling-sdk';
8+
import {getApiErrorMessage, type OdsComponents} from '@salesforce/b2c-tooling-sdk';
99
import {t} from '../../i18n/index.js';
1010

1111
type SandboxModel = OdsComponents['schemas']['SandboxModel'];
@@ -142,11 +142,9 @@ export default class OdsList extends OdsCommand<typeof OdsList> {
142142
});
143143

144144
if (result.error) {
145-
const errorResponse = result.error as OdsComponents['schemas']['ErrorResponse'] | undefined;
146-
const errorMessage = errorResponse?.error?.message || result.response?.statusText || 'Unknown error';
147145
this.error(
148146
t('commands.ods.list.error', 'Failed to fetch sandboxes: {{message}}', {
149-
message: errorMessage,
147+
message: getApiErrorMessage(result.error, result.response),
150148
}),
151149
);
152150
}

packages/b2c-cli/src/commands/ods/restart.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
import {Args} from '@oclif/core';
77
import {OdsCommand} from '@salesforce/b2c-tooling-sdk/cli';
8-
import type {OdsComponents} from '@salesforce/b2c-tooling-sdk';
8+
import {getApiErrorMessage, type OdsComponents} from '@salesforce/b2c-tooling-sdk';
99
import {t} from '../../i18n/index.js';
1010

1111
type SandboxOperationModel = OdsComponents['schemas']['SandboxOperationModel'];
@@ -45,11 +45,9 @@ export default class OdsRestart extends OdsCommand<typeof OdsRestart> {
4545
});
4646

4747
if (!result.data?.data) {
48-
const errorResponse = result.error as OdsComponents['schemas']['ErrorResponse'] | undefined;
49-
const errorMessage = errorResponse?.error?.message || result.response?.statusText || 'Unknown error';
5048
this.error(
5149
t('commands.ods.restart.error', 'Failed to restart sandbox: {{message}}', {
52-
message: errorMessage,
50+
message: getApiErrorMessage(result.error, result.response),
5351
}),
5452
);
5553
}

packages/b2c-cli/src/commands/ods/start.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
import {Args} from '@oclif/core';
77
import {OdsCommand} from '@salesforce/b2c-tooling-sdk/cli';
8-
import type {OdsComponents} from '@salesforce/b2c-tooling-sdk';
8+
import {getApiErrorMessage, type OdsComponents} from '@salesforce/b2c-tooling-sdk';
99
import {t} from '../../i18n/index.js';
1010

1111
type SandboxOperationModel = OdsComponents['schemas']['SandboxOperationModel'];
@@ -45,11 +45,9 @@ export default class OdsStart extends OdsCommand<typeof OdsStart> {
4545
});
4646

4747
if (!result.data?.data) {
48-
const errorResponse = result.error as OdsComponents['schemas']['ErrorResponse'] | undefined;
49-
const errorMessage = errorResponse?.error?.message || result.response?.statusText || 'Unknown error';
5048
this.error(
5149
t('commands.ods.start.error', 'Failed to start sandbox: {{message}}', {
52-
message: errorMessage,
50+
message: getApiErrorMessage(result.error, result.response),
5351
}),
5452
);
5553
}

packages/b2c-cli/src/commands/ods/stop.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
import {Args} from '@oclif/core';
77
import {OdsCommand} from '@salesforce/b2c-tooling-sdk/cli';
8-
import type {OdsComponents} from '@salesforce/b2c-tooling-sdk';
8+
import {getApiErrorMessage, type OdsComponents} from '@salesforce/b2c-tooling-sdk';
99
import {t} from '../../i18n/index.js';
1010

1111
type SandboxOperationModel = OdsComponents['schemas']['SandboxOperationModel'];
@@ -45,11 +45,9 @@ export default class OdsStop extends OdsCommand<typeof OdsStop> {
4545
});
4646

4747
if (!result.data?.data) {
48-
const errorResponse = result.error as OdsComponents['schemas']['ErrorResponse'] | undefined;
49-
const errorMessage = errorResponse?.error?.message || result.response?.statusText || 'Unknown error';
5048
this.error(
5149
t('commands.ods.stop.error', 'Failed to stop sandbox: {{message}}', {
52-
message: errorMessage,
50+
message: getApiErrorMessage(result.error, result.response),
5351
}),
5452
);
5553
}

packages/b2c-cli/src/commands/scapi/custom/status.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
*/
66
import {Command, Flags, ux} from '@oclif/core';
77
import {OAuthCommand, TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli';
8-
import {createCustomApisClient, toOrganizationId, type CustomApisComponents} from '@salesforce/b2c-tooling-sdk';
8+
import {
9+
createCustomApisClient,
10+
getApiErrorMessage,
11+
toOrganizationId,
12+
type CustomApisComponents,
13+
} from '@salesforce/b2c-tooling-sdk';
914
import {t} from '../../../i18n/index.js';
1015

1116
type CustomApiEndpoint = CustomApisComponents['schemas']['CustomApiEndpoint'];
@@ -242,7 +247,11 @@ export default class ScapiCustomStatus extends ScapiCustomCommand<typeof ScapiCu
242247
// Ensure organizationId has the required f_ecom_ prefix
243248
const organizationId = toOrganizationId(tenantId);
244249

245-
const {data, error} = await client.GET('/organizations/{organizationId}/endpoints', {
250+
const {
251+
data,
252+
error,
253+
response: httpResponse,
254+
} = await client.GET('/organizations/{organizationId}/endpoints', {
246255
params: {
247256
path: {organizationId},
248257
query: status ? {status: status as 'active' | 'not_registered'} : undefined,
@@ -252,7 +261,7 @@ export default class ScapiCustomStatus extends ScapiCustomCommand<typeof ScapiCu
252261
if (error) {
253262
this.error(
254263
t('commands.scapi.custom.status.error', 'Failed to fetch Custom API endpoints: {{message}}', {
255-
message: typeof error === 'object' ? JSON.stringify(error) : String(error),
264+
message: getApiErrorMessage(error, httpResponse),
256265
}),
257266
);
258267
}

packages/b2c-cli/src/commands/scapi/schemas/get.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export default class ScapiSchemasGet extends ScapiSchemasCommand<typeof ScapiSch
168168

169169
const client = this.getSchemasClient();
170170

171-
const {data, error} = await client.GET(
171+
const {data, error, response} = await client.GET(
172172
'/organizations/{organizationId}/schemas/{apiFamily}/{apiName}/{apiVersion}',
173173
{
174174
params: {
@@ -186,7 +186,7 @@ export default class ScapiSchemasGet extends ScapiSchemasCommand<typeof ScapiSch
186186
if (error) {
187187
this.error(
188188
t('commands.scapi.schemas.get.error', 'Failed to fetch schema: {{message}}', {
189-
message: formatApiError(error),
189+
message: formatApiError(error, response),
190190
}),
191191
);
192192
}

packages/b2c-cli/src/commands/scapi/schemas/list.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export default class ScapiSchemasList extends ScapiSchemasCommand<typeof ScapiSc
106106

107107
const client = this.getSchemasClient();
108108

109-
const {data, error} = await client.GET('/organizations/{organizationId}/schemas', {
109+
const {data, error, response} = await client.GET('/organizations/{organizationId}/schemas', {
110110
params: {
111111
path: {organizationId: this.getOrganizationId()},
112112
query: {
@@ -121,7 +121,7 @@ export default class ScapiSchemasList extends ScapiSchemasCommand<typeof ScapiSc
121121
if (error) {
122122
this.error(
123123
t('commands.scapi.schemas.list.error', 'Failed to fetch SCAPI schemas: {{message}}', {
124-
message: formatApiError(error),
124+
message: formatApiError(error, response),
125125
}),
126126
);
127127
}

0 commit comments

Comments
 (0)