Skip to content

Commit 7dad107

Browse files
fix(wiza): surface Wiza's nested error messages (#8532)
* fix(wiza): surface Wiza's nested error messages * fix(wiza): keep plain-text errors and parse reveal polling failures * fix(wiza): only accept trimmed string messages in error extractor
1 parent b6a598e commit 7dad107

6 files changed

Lines changed: 79 additions & 1 deletion

File tree

‎apps/sim/tools/error-extractors.test.ts‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,46 @@ describe('Error Extractors', () => {
362362
)
363363
})
364364
})
365+
366+
describe('wiza-errors', () => {
367+
it('extracts the message nested under status', () => {
368+
const errorInfo: ErrorInfo = {
369+
status: 400,
370+
statusText: 'Bad Request',
371+
data: { status: { code: 400, message: 'The size parameter is not allowed.' } },
372+
}
373+
374+
expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe(
375+
'The size parameter is not allowed.'
376+
)
377+
})
378+
379+
it('falls back to a top-level message', () => {
380+
const errorInfo: ErrorInfo = { status: 401, data: { message: 'Unauthorized' } }
381+
382+
expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe('Unauthorized')
383+
})
384+
385+
it('keeps plain-text bodies', () => {
386+
const errorInfo: ErrorInfo = { status: 502, data: 'Bad gateway' }
387+
388+
expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe('Bad gateway')
389+
})
390+
391+
it('ignores a non-string top-level message', () => {
392+
const errorInfo: ErrorInfo = { status: 422, data: { message: ['bad filter'] } }
393+
394+
expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe(
395+
'Request failed with status 422'
396+
)
397+
})
398+
399+
it('falls back to the status when Wiza sends an empty message', () => {
400+
const errorInfo: ErrorInfo = { status: 400, data: { status: { code: 400, message: '' } } }
401+
402+
expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe(
403+
'Request failed with status 400'
404+
)
405+
})
406+
})
365407
})

‎apps/sim/tools/error-extractors.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,20 @@ const ERROR_EXTRACTORS: ErrorExtractorConfig[] = [
514514
return parts.length > 0 ? parts.join(': ') : undefined
515515
},
516516
},
517+
{
518+
id: 'wiza-errors',
519+
description:
520+
'Wiza API error envelope: {status: {code, message}}, plus plain-text bodies. The message is nested under status, so the generic extractors miss it',
521+
examples: ['Wiza'],
522+
extract: (errorInfo) => {
523+
const data = errorInfo?.data
524+
const candidates = [data, data?.status?.message, data?.message]
525+
for (const candidate of candidates) {
526+
if (typeof candidate === 'string' && candidate.trim()) return candidate.trim()
527+
}
528+
return undefined
529+
},
530+
},
517531
{
518532
id: 'crunchbase-errors',
519533
description:
@@ -680,6 +694,7 @@ export const ErrorExtractorId = {
680694
POSTHOG_ERRORS: 'posthog-errors',
681695
QUICKBOOKS_FAULT: 'quickbooks-fault',
682696
PROSPEO_ERRORS: 'prospeo-errors',
697+
WIZA_ERRORS: 'wiza-errors',
683698
CRUNCHBASE_ERRORS: 'crunchbase-errors',
684699
PITCHBOOK_ERRORS: 'pitchbook-errors',
685700
SPLUNK_ERRORS: 'splunk-errors',

‎apps/sim/tools/wiza/company_enrichment.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ErrorExtractorId } from '@/tools/error-extractors'
12
import type { ToolConfig } from '@/tools/types'
23
import { wizaHosting } from '@/tools/wiza/hosting'
34
import type { WizaCompanyEnrichmentParams, WizaCompanyEnrichmentResponse } from '@/tools/wiza/types'
@@ -11,6 +12,7 @@ export const wizaCompanyEnrichmentTool: ToolConfig<
1112
description:
1213
'Enrich a company by name, domain, LinkedIn ID, or LinkedIn slug with detailed firmographic data',
1314
version: '1.0.0',
15+
errorExtractor: ErrorExtractorId.WIZA_ERRORS,
1416

1517
hosting: wizaHosting<WizaCompanyEnrichmentParams>((_params, output) => {
1618
// 2 API credits per successful company match; no charge on a no-match.

‎apps/sim/tools/wiza/get_credits.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ErrorExtractorId } from '@/tools/error-extractors'
12
import type { ToolConfig } from '@/tools/types'
23
import type { WizaGetCreditsParams, WizaGetCreditsResponse } from '@/tools/wiza/types'
34

@@ -6,6 +7,7 @@ export const wizaGetCreditsTool: ToolConfig<WizaGetCreditsParams, WizaGetCredits
67
name: 'Wiza Get Credits',
78
description: 'Retrieve the remaining credits on your Wiza account',
89
version: '1.0.0',
10+
errorExtractor: ErrorExtractorId.WIZA_ERRORS,
911

1012
params: {
1113
apiKey: {

‎apps/sim/tools/wiza/individual_reveal.ts‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { sleep } from '@sim/utils/helpers'
2+
import { ErrorExtractorId, extractErrorMessage } from '@/tools/error-extractors'
23
import type { ToolConfig } from '@/tools/types'
34
import { wizaHosting } from '@/tools/wiza/hosting'
45
import type {
@@ -77,6 +78,7 @@ export const wizaIndividualRevealTool: ToolConfig<
7778
description:
7879
'Reveal a contact via LinkedIn URL, name + company/domain, or email. Starts the reveal and polls until it resolves. Uses 2 credits per valid email and 5 credits per phone, charged only on success.',
7980
version: '1.0.0',
81+
errorExtractor: ErrorExtractorId.WIZA_ERRORS,
8082

8183
hosting: wizaHosting<WizaIndividualRevealParams>((_params, output) => {
8284
let credits = 0
@@ -238,9 +240,22 @@ export const wizaIndividualRevealTool: ToolConfig<
238240
consecutiveErrors += 1
239241
if (consecutiveErrors >= MAX_CONSECUTIVE_POLL_ERRORS) {
240242
const errorText = await statusResponse.text().catch(() => '')
243+
let errorData: unknown
244+
try {
245+
errorData = JSON.parse(errorText)
246+
} catch {
247+
errorData = errorText
248+
}
241249
return {
242250
success: false,
243-
error: `Wiza API error: ${statusResponse.status} - ${errorText}`,
251+
error: extractErrorMessage(
252+
{
253+
status: statusResponse.status,
254+
statusText: statusResponse.statusText,
255+
data: errorData,
256+
},
257+
ErrorExtractorId.WIZA_ERRORS
258+
),
244259
output: result.output,
245260
}
246261
}

‎apps/sim/tools/wiza/prospect_search.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isRecordLike } from '@sim/utils/object'
2+
import { ErrorExtractorId } from '@/tools/error-extractors'
23
import type { ToolConfig } from '@/tools/types'
34
import { wizaHosting } from '@/tools/wiza/hosting'
45
import type { WizaProspectSearchParams, WizaProspectSearchResponse } from '@/tools/wiza/types'
@@ -11,6 +12,7 @@ export const wizaProspectSearchTool: ToolConfig<
1112
name: 'Wiza Prospect Search',
1213
description: "Search Wiza's database of prospects using person, company, and financial filters",
1314
version: '1.0.0',
15+
errorExtractor: ErrorExtractorId.WIZA_ERRORS,
1416

1517
hosting: wizaHosting<WizaProspectSearchParams>(() => {
1618
// Prospect search returns profiles without contact data and consumes no credits;

0 commit comments

Comments
 (0)