{"record":{"id":"50beea8a718dc33a","repo":"can1357/oh-my-pi","slug":"an-unknown-error-occurred-50beea","errorCode":null,"errorMessage":"An unknown error occurred","messagePattern":"An unknown error occurred","errorType":"exception","errorClass":"AIError.ProviderResponseError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/google-shared.ts","lineNumber":774,"sourceCode":"\t\t\tcalculateCost(model, output.usage);\n\t\t}\n\t}\n\n\tflushCurrent();\n\n\tif (options?.signal?.aborted) {\n\t\tthrow new AIError.AbortError();\n\t}\n\n\tif (!sawFinishReason) {\n\t\tthrow new AIError.ProviderResponseError(\n\t\t\t\"Google API stream ended without a finish reason (connection dropped or response truncated)\",\n\t\t\t{ provider: model.provider, kind: \"incomplete-stream\" },\n\t\t);\n\t}\n\n\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\tthrow new AIError.ProviderResponseError(output.errorMessage ?? \"An unknown error occurred\", {\n\t\t\tprovider: model.provider,\n\t\t\tkind: \"output\",\n\t\t});\n\t}\n}\n\n/**\n * Generation/sampling fields that map directly onto Gemini's `GenerateContentConfig`.\n * Excludes any provider-specific extensions (`topP`/`topK`/etc are all forwarded as-is).\n */\ninterface GoogleGenerationConfig extends GenerateContentConfig {\n\ttopP?: number;\n\ttopK?: number;\n\tminP?: number;\n\tpresencePenalty?: number;\n\trepetitionPenalty?: number;\n}\n","sourceCodeStart":756,"sourceCodeEnd":792,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/google-shared.ts#L756-L792","documentation":"consumeGoogleStream completed with output.stopReason \"aborted\" or \"error\" and output.errorMessage was not populated, so this generic fallback text is thrown as AIError.ProviderResponseError (kind \"output\"). The Google stream signalled a failed terminal state without a reason string.","triggerScenarios":"Final chunk carries finishReason mapping to \"error\" (e.g. MALFORMED_FUNCTION_CALL, LANGUAGE, UNEXPECTED_TOOL_CALL, NO_IMAGE) or \"aborted\" (user abort via signal), and errorMessage was never set from prior error chunks.","commonSituations":"Model emits a malformed function call that Google terminates with MALFORMED_FUNCTION_CALL; user aborts mid-generation (check signal first); Google internal error terminations with no message.","solutions":["If stopReason is \"aborted\", verify options.signal — this may be an intentional user abort, handle it as AbortError instead of a provider failure","Capture partial output/accumulated chunks before the throw to diagnose what the model produced","Retry on \"error\" stop reasons like MALFORMED_FUNCTION_CALL; reduce or fix tool schemas to avoid malformed calls","Check Google service status for backend incidents"],"exampleFix":"// before\nif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n  throw new AIError.ProviderResponseError(output.errorMessage ?? \"An unknown error occurred\", { provider: model.provider, kind: \"output\" });\n}\n// after\nif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n  throw new AIError.ProviderResponseError(\n    output.errorMessage ?? `Google stream ended with stopReason=${output.stopReason}`,\n    { provider: model.provider, kind: \"output\" },\n  );\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"function isAbortOrErrorStop(o: { stopReason: string }): boolean {\n  return o.stopReason === \"aborted\" || o.stopReason === \"error\";\n}","tryCatchPattern":"try {\n  await streamGoogle(model, params, { signal });\n} catch (err) {\n  if (err instanceof AIError.AbortError || signal.aborted) throw err; // user-intent abort\n  if (err instanceof AIError.ProviderResponseError && err.context?.kind === \"output\" && err.message === \"An unknown error occurred\") {\n    logger.warn(\"google stream failed without message; retrying\", {});\n    return withBackoff(() => streamGoogle(model, params, { signal }));\n  }\n  throw err;\n}","preventionTips":["Check signal.aborted first so intentional aborts aren't mistaken for provider failures","Validate/normalize tool schemas (JSON Schema) to reduce MALFORMED_FUNCTION_CALL terminations","Keep accumulated partial text so a failed stream still yields usable content","Retry with backoff on unexplained error stop reasons"],"tags":["google","streaming","malformed-function-call","abort"],"backgroundTag":"opaque-provider-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}