alibaba/page-agent · error · InvokeError

CONFIG_ERROR

CONFIG_ERROR

Error message

transformRequestBody failed: ${(error as Error).message}

What it means

Thrown when the user-supplied transformRequestBody config callback raises an exception while transforming the outgoing request body. The library treats a failing request transformer as a configuration problem, not a runtime model failure. The original error is preserved as the cause.

Source

Thrown at packages/llms/src/OpenAIClient.ts:65

		const requestBody: Record<string, unknown> = {
			model: this.config.model,
			messages,
			tools: openaiTools,
			parallel_tool_calls: false,
			tool_choice: toolChoice,
		}
		// Only sent if the caller explicitly set it. Most new models throw if this is set.
		if (this.config.temperature !== undefined) {
			requestBody.temperature = this.config.temperature
		}

		modelPatch(requestBody, this.config.baseURL)

		let transformedBody: Record<string, unknown> | undefined
		try {
			transformedBody = this.config.transformRequestBody(requestBody)
		} catch (error) {
			throw new InvokeError(
				InvokeErrorTypes.CONFIG_ERROR,
				`transformRequestBody failed: ${(error as Error).message}`,
				error
			)
		}
		const finalRequestBody = transformedBody ?? requestBody

		// 2. Call API
		let response: Response
		try {
			response = await this.fetch(`${this.config.baseURL}/chat/completions`, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json',
					...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }),
				},
				body: JSON.stringify(finalRequestBody),
				signal: abortSignal,

View on GitHub (pinned to d02db1ee7c)

Solutions

  1. Inspect the preserved cause: catch (e) { e.cause } — the stack points at the exact line in your transformRequestBody that threw
  2. Make the transformer defensive: use optional chaining and only patch fields that exist
  3. Log or assert the requestBody shape once in dev to confirm the transformer's assumptions
  4. If no transformation is needed, omit transformRequestBody from the config entirely

Example fix

// before
new OpenAIClient({ ..., transformRequestBody: (body) => {
  body.messages[0].content = body.messages[0].content.toUpperCase() // throws if content is undefined
}})

// after
new OpenAIClient({ ..., transformRequestBody: (body) => {
  if (Array.isArray(body.messages) && typeof body.messages[0]?.content === 'string') {
    body.messages[0].content = body.messages[0].content.toUpperCase()
  }
  return body
}})
Defensive patterns

Strategy: validation

Validate before calling

const body = { model: 'gpt-4o', messages: [{ role: 'user', content: 'hi' }] }
// dry-run the transformer before wiring it in
const out = config.transformRequestBody(body)
if (!out || typeof out !== 'object') throw new Error('transformRequestBody must return an object')

Type guard

const isInvokeConfigError = (e: unknown): e is InvokeError =>
  e instanceof InvokeError && e.code === 'CONFIG_ERROR'

Try / catch

try {
  await client.invoke(req)
} catch (e) {
  if (isInvokeConfigError(e)) {
    console.error('Transformer bug:', (e as InvokeError).cause)
    throw e // config bugs are deterministic — do not retry
  }
  throw e
}

Prevention

When it happens

Trigger: Setting config.transformRequestBody to a function that throws — e.g. it assumes a field exists on the body (requestBody.messages[0].content.replace(...)), mutates a frozen object, or contains a typo'd property access. It runs on every invoke() before the HTTP call, after modelPatch().

Common situations: A transformer written for one provider's schema (e.g. OpenAI 'messages') is used against a body shape another provider produces; transformer accesses undefined nested fields; transformer uses JSON.parse on an already-object value; SDK upgrade changes requestBody shape the transformer relied on.

Related errors


AI-assisted analysis of alibaba/page-agent@d02db1ee7c (2026-08-28). Data as JSON: /api/errors/e398bde0068df818. Report an issue: GitHub.