CherryHQ/cherry-studio · error · Error
typeof failure === 'string' ? failure : JSON.stringify(failu
Error message
typeof failure === 'string' ? failure : JSON.stringify(failure ?? 'unknown error')
What it means
Thrown by runFormulaFiber() when a Kimi (Moonshot) formula fiber call does not yield usable output: status !== 'succeeded', or succeeded but with empty output/encrypted_output. The message is the fiber's own error payload (stringified if structured). It surfaces as a tool-execution failure so the SDK marks the tool part failed rather than returning an empty 'search returned nothing' result.
Source
Thrown at src/main/ai/provider/custom/moonshotProvider.ts:60
args: unknown
): Promise<string> {
const doFetch = settings.fetch ?? globalThis.fetch
const response = await doFetch(`${withoutTrailingSlash(settings.baseURL)}/formulas/${formulaUri}/fibers`, {
method: 'POST',
headers: { Authorization: `Bearer ${settings.apiKey}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, arguments: JSON.stringify(args ?? {}) })
})
const fiber = (await response.json().catch(() => ({}))) as FormulaFiber
if (fiber.status === 'succeeded') {
const output = fiber.context?.output || fiber.context?.encrypted_output
if (output) return output
}
// Throw rather than returning an "Error: …" string as a normal result: the SDK still hands the
// message to the model, and the tool part is marked failed instead of masquerading as a search
// that returned nothing.
const failure = fiber.error ?? fiber.context?.error ?? fiber.context?.output
throw new Error(typeof failure === 'string' ? failure : JSON.stringify(failure ?? 'unknown error'))
}
/**
* The declaration mirrors `GET /formulas/moonshot/web-search:latest/tools`. It is inlined because the
* AI SDK needs the schema synchronously when the tool set is built; the fiber call is what actually
* runs the search, so a drifted description costs nothing.
*/
export interface KimiFormulaCredentials {
apiKey?: string
baseURL?: string
fetch?: FetchFunction
}
/** Build the tool from this request's serving credential (see the factory in extensions.ts). */
export function createKimiWebSearchToolFor(credentials: KimiFormulaCredentials) {
return createKimiWebSearchTool((args) =>
runFormulaFiber(
{View on GitHub (pinned to 726446b54c)
Solutions
- Inspect the thrown message: a 401-flavored error means the apiKey is wrong/missing; a rate-limit message means back off; an 'unauthorized formula' message means enable web-search in the Kimi account.
- Confirm credentials.baseURL resolves to https://api.moonshot.cn/v1 (or the matching region) and that /formulas/.../fibers is reachable.
- Verify the tool input shape matches { query: string }; re-encoding via JSON.stringify(args) must produce the contract the fiber expects.
- If the fiber is protected and returns no encrypted_output, fall back to a non-formula search path or instruct the user to grant the scope.
Example fix
// before
const out = await runFormulaFiber(creds, uri, name, args)
// after — guard the fiber shape and rethrow a typed error
const resp = await doFetch(...)
const fiber = await resp.json().catch(() => ({}))
if (fiber.status !== 'succeeded' || !(fiber.context?.output || fiber.context?.encrypted_output)) {
throw new Error(`Kimi fiber '${uri}' failed: ${typeof fiber.error === 'string' ? fiber.error : JSON.stringify(fiber.error ?? fiber)}`)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate credentials and input shape before the fiber call
if (!settings.apiKey) throw new Error('Moonshot apiKey is required')
if (typeof args !== 'object' || args === null || typeof (args as any).query !== 'string') {
throw new Error('Kimi web-search fiber requires { query: string }')
} Type guard
export function isFiberFailure(e: unknown): boolean {
return e instanceof Error && /fiber|Kimi|moonshot/i.test(e.message)
} Try / catch
try {
await runFormulaFiber(creds, uri, name, args)
} catch (e) {
// Surface as a tool-error result so the model sees the reason
return { toolResult: { error: e instanceof Error ? e.message : String(e) } }
} Prevention
- Confirm web-search formula is enabled for the Moonshot account before relying on it.
- Keep the tool input shape ({ query: string }) in sync with the formula contract.
- Return fiber failures as tool-error results rather than swallowing them — the model adapts.
When it happens
Trigger: POST /formulas/{uri}/fibers returns { status: 'failed' } or { error: ... } or a succeeded fiber with empty output/encrypted_output. Concrete causes: invalid/expired Moonshot apiKey, web-search formula disabled for the account, rate limit on the formula channel, malformed arguments JSON, or the protected formula's encrypted_output requires a session the key doesn't have.
Common situations: First use of Kimi web-search tool with an unprivileged key, baseURL pointing at a non-formula endpoint, arguments schema drift (e.g. { query } renamed), or account not whitelisted for protected formulas.
Related errors
- QQ API request failed ${endpoint}: HTTP ${response.status} -
- Brave API error: ${response.status} ${response.statusText}\n
- Brave API error: ${webResponse.status} ${webResponse.statusT
- Invalid response format from Dify API: ${JSON.stringify(sear
- 0
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/de8fb0d6dac1cf12.
Report an issue: GitHub.