google.genai.errors.ClientError: 400 Bad Request. {'message': '{\n "error": {\n "code": 400,\n "message": "* GenerateContentRequest.tools[0].function_declarations[9].parameters.properties[payload].any_of[1].items: missing field.\\n",\n "status": "INVALID_ARGUMENT"\n }\n}\n', 'status': 'Bad Request'}
items object (Schema)
Optional. Schema of the elements of Type.ARRAY.
[21:44:02.444] [Core] [WARN] [v4.20.0] [runners.tool_loop_agent_runner:268]: Chat Model google_gemini/gemini-2.5-flash request error: 400 Bad Request. {'message': '{\n "error": {\n "code": 400,\n "message": "* GenerateContentRequest.tools[0].function_declarations[9].parameters.properties[payload].any_of[1].items: missing field.\\n",\n "status": "INVALID_ARGUMENT"\n }\n}\n', 'status': 'Bad Request'}
Traceback (most recent call last):
File "/home/saite/project/AstrBot/main.py", line 141, in <module>
asyncio.run(main_async(args.webui_dir))
│ │ │ │ └ None
│ │ │ └ Namespace(webui_dir=None)
│ │ └ <function main_async at 0x7fac6de3d800>
│ └ <function run at 0x7fac6f521f80>
└ <module 'asyncio' from '/home/saite/.pyenv/versions/3.12.11/lib/python3.12/asyncio/__init__.py'>
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/asyncio/runners.py", line 195, in run
return runner.run(main)
│ │ └ <coroutine object main_async at 0x7fac6bc1da80>
│ └ <function Runner.run at 0x7fac6ed27420>
└ <asyncio.runners.Runner object at 0x7fac07b55af0>
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
│ │ │ └ <Task pending name='Task-1' coro=<main_async() running at /home/saite/project/AstrBot/main.py:121> wait_for=<_GatheringFuture...
│ │ └ <function BaseEventLoop.run_until_complete at 0x7fac6ed25080>
│ └ <_UnixSelectorEventLoop running=True closed=False debug=False>
└ <asyncio.runners.Runner object at 0x7fac07b55af0>
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/asyncio/base_events.py", line 678, in run_until_complete
self.run_forever()
│ └ <function BaseEventLoop.run_forever at 0x7fac6ed24fe0>
└ <_UnixSelectorEventLoop running=True closed=False debug=False>
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/asyncio/base_events.py", line 645, in run_forever
self._run_once()
│ └ <function BaseEventLoop._run_once at 0x7fac6ed26de0>
└ <_UnixSelectorEventLoop running=True closed=False debug=False>
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/asyncio/base_events.py", line 1999, in _run_once
handle._run()
│ └ <function Handle._run at 0x7fac6f4c1120>
└ <Handle Task.task_wakeup(<Future finished result=None>)>
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
│ │ │ │ │ └ <member '_args' of 'Handle' objects>
│ │ │ │ └ <Handle Task.task_wakeup(<Future finished result=None>)>
│ │ │ └ <member '_callback' of 'Handle' objects>
│ │ └ <Handle Task.task_wakeup(<Future finished result=None>)>
│ └ <member '_context' of 'Handle' objects>
└ <Handle Task.task_wakeup(<Future finished result=None>)>
File "/home/saite/project/AstrBot/astrbot/core/pipeline/scheduler.py", line 87, in execute
await self._process_stages(event)
│ │ └ <astrbot.core.platform.sources.webchat.webchat_event.WebChatMessageEvent object at 0x7fac0447e5d0>
│ └ <function PipelineScheduler._process_stages at 0x7fac07da51c0>
└ <astrbot.core.pipeline.scheduler.PipelineScheduler object at 0x7fac6bdaaa80>
File "/home/saite/project/AstrBot/astrbot/core/pipeline/scheduler.py", line 61, in _process_stages
await self._process_stages(event, i + 1)
│ │ │ └ 6
│ │ └ <astrbot.core.platform.sources.webchat.webchat_event.WebChatMessageEvent object at 0x7fac0447e5d0>
│ └ <function PipelineScheduler._process_stages at 0x7fac07da51c0>
└ <astrbot.core.pipeline.scheduler.PipelineScheduler object at 0x7fac6bdaaa80>
File "/home/saite/project/AstrBot/astrbot/core/pipeline/scheduler.py", line 72, in _process_stages
await coroutine
└ <coroutine object RespondStage.process at 0x7fac057ee6c0>
File "/home/saite/project/AstrBot/astrbot/core/pipeline/respond/stage.py", line 201, in process
await event.send_streaming(result.async_stream, realtime_segmenting)
│ │ │ │ └ True
│ │ │ └ <async_generator object run_agent at 0x7fac0443c4f0>
│ │ └ MessageEventResult(chain=[], use_t2i_=None, type=None, result_type=<EventResultType.CONTINUE: 1>, result_content_type=<Result...
│ └ <function WebChatMessageEvent.send_streaming at 0x7fac07e760c0>
└ <astrbot.core.platform.sources.webchat.webchat_event.WebChatMessageEvent object at 0x7fac0447e5d0>
File "/home/saite/project/AstrBot/astrbot/core/platform/sources/webchat/webchat_event.py", line 147, in send_streaming
async for chain in generator:
└ <async_generator object run_agent at 0x7fac0443c4f0>
File "/home/saite/project/AstrBot/astrbot/core/astr_agent_run_util.py", line 124, in run_agent
async for resp in agent_runner.step():
│ └ <function ToolLoopAgentRunner.step at 0x7fac631c89a0>
└ <astrbot.core.agent.runners.tool_loop_agent_runner.ToolLoopAgentRunner object at 0x7fac0699a180>
File "/home/saite/project/AstrBot/astrbot/core/agent/runners/tool_loop_agent_runner.py", line 374, in step
async for llm_response in self._iter_llm_responses_with_fallback():
│ └ <function ToolLoopAgentRunner._iter_llm_responses_with_fallback at 0x7fac631c85e0>
└ <astrbot.core.agent.runners.tool_loop_agent_runner.ToolLoopAgentRunner object at 0x7fac0699a180>
> File "/home/saite/project/AstrBot/astrbot/core/agent/runners/tool_loop_agent_runner.py", line 243, in _iter_llm_responses_with_fallback
async for resp in self._iter_llm_responses(include_model=idx == 0):
│ │ └ 0
│ └ <function ToolLoopAgentRunner._iter_llm_responses at 0x7fac631c8540>
└ <astrbot.core.agent.runners.tool_loop_agent_runner.ToolLoopAgentRunner object at 0x7fac0699a180>
File "/home/saite/project/AstrBot/astrbot/core/agent/runners/tool_loop_agent_runner.py", line 217, in _iter_llm_responses
async for resp in stream: # type: ignore
└ <async_generator object ProviderGoogleGenAI.text_chat_stream at 0x7fac05641840>
File "/home/saite/project/AstrBot/astrbot/core/provider/sources/gemini_source.py", line 844, in text_chat_stream
if await self._handle_api_error(e, keys):
│ │ └ ['<REDACTED>']
│ └ <function ProviderGoogleGenAI._handle_api_error at 0x7fac06892700>
└ <astrbot.core.provider.sources.gemini_source.ProviderGoogleGenAI object at 0x7fac069bcf80>
File "/home/saite/project/AstrBot/astrbot/core/provider/sources/gemini_source.py", line 128, in _handle_api_error
raise e
└ ClientError('400 Bad Request. {\'message\': \'{\\n "error": {\\n "code": 400,\\n "message": "* GenerateContentRequest....
File "/home/saite/project/AstrBot/astrbot/core/provider/sources/gemini_source.py", line 840, in text_chat_stream
async for response in self._query_stream(payloads, func_tool):
│ │ │ └ ToolSet(tools=[ExecuteShellTool(name='astrbot_execute_shell', description='Execute a command in the shell.', parameters={'typ...
│ │ └ {'messages': [{'role': 'system', 'content': '\n# Persona Instructions\n\nYou are a helpful and friendly assistant.\n\n[Shipya...
│ └ <function ProviderGoogleGenAI._query_stream at 0x7fac06892b60>
└ <astrbot.core.provider.sources.gemini_source.ProviderGoogleGenAI object at 0x7fac069bcf80>
File "/home/saite/project/AstrBot/astrbot/core/provider/sources/gemini_source.py", line 639, in _query_stream
result = await self.client.models.generate_content_stream(
│ │ └ <property object at 0x7fac6852d7b0>
│ └ <google.genai.client.AsyncClient object at 0x7fac068a3950>
└ <astrbot.core.provider.sources.gemini_source.ProviderGoogleGenAI object at 0x7fac069bcf80>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/models.py", line 7699, in generate_content_stream
response = await self._generate_content_stream(
│ └ <function AsyncModels._generate_content_stream at 0x7fac689332e0>
└ <google.genai.models.AsyncModels object at 0x7fac068a4bc0>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/models.py", line 6423, in _generate_content_stream
response_stream = await self._api_client.async_request_streamed(
│ │ └ <function BaseApiClient.async_request_streamed at 0x7fac68a99580>
│ └ <google.genai._api_client.BaseApiClient object at 0x7fac07c7ce30>
└ <google.genai.models.AsyncModels object at 0x7fac068a4bc0>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/_api_client.py", line 1464, in async_request_streamed
response = await self._async_request(
│ └ <function BaseApiClient._async_request at 0x7fac68a99260>
└ <google.genai._api_client.BaseApiClient object at 0x7fac07c7ce30>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/_api_client.py", line 1380, in _async_request
return await self._async_retry( # type: ignore[no-any-return]
│ └ <AsyncRetrying object at 0x7fac068a0b90 (stop=<tenacity.stop.stop_after_attempt object at 0x7fac068a61b0>, wait=<tenacity.wai...
└ <google.genai._api_client.BaseApiClient object at 0x7fac07c7ce30>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/tenacity/asyncio/__init__.py", line 112, in __call__
do = await self.iter(retry_state=retry_state)
│ │ └ <RetryCallState 140376782464272: attempt #1; slept for 0.0; last result: failed (ClientError 400 Bad Request. {'message': '{\...
│ └ <function AsyncRetrying.iter at 0x7fac689ffa60>
└ <AsyncRetrying object at 0x7fac068a0b90 (stop=<tenacity.stop.stop_after_attempt object at 0x7fac068a61b0>, wait=<tenacity.wai...
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/tenacity/asyncio/__init__.py", line 157, in iter
result = await action(retry_state)
│ └ <RetryCallState 140376782464272: attempt #1; slept for 0.0; last result: failed (ClientError 400 Bad Request. {'message': '{\...
└ <function wrap_to_async_func.<locals>.inner at 0x7fac043962a0>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/tenacity/_utils.py", line 111, in inner
return call(*args, **kwargs)
│ │ └ {}
│ └ (<RetryCallState 140376782464272: attempt #1; slept for 0.0; last result: failed (ClientError 400 Bad Request. {'message': '{...
└ <function BaseRetrying._post_stop_check_actions.<locals>.exc_check at 0x7fac04395da0>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 413, in exc_check
raise retry_exc.reraise()
│ └ <function RetryError.reraise at 0x7fac689fcd60>
└ RetryError(<Future at 0x7fac0440df70 state=finished raised ClientError>)
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 184, in reraise
raise self.last_attempt.result()
│ │ └ <function Future.result at 0x7fac6f8efba0>
│ └ <Future at 0x7fac0440df70 state=finished raised ClientError>
└ RetryError(<Future at 0x7fac0440df70 state=finished raised ClientError>)
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/concurrent/futures/_base.py", line 449, in result
return self.__get_result()
└ None
File "/home/saite/.pyenv/versions/3.12.11/lib/python3.12/concurrent/futures/_base.py", line 401, in __get_result
raise self._exception
└ None
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/tenacity/asyncio/__init__.py", line 116, in __call__
result = await fn(*args, **kwargs)
│ │ └ {}
│ └ (HttpRequest(headers={'Content-Type': 'application/json', 'x-goog-api-key': '<REDACTED>', 'user-...
└ <bound method BaseApiClient._async_request_once of <google.genai._api_client.BaseApiClient object at 0x7fac07c7ce30>>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/_api_client.py", line 1296, in _async_request_once
await errors.APIError.raise_for_async_response(response)
│ │ │ └ <ClientResponse(https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse) [400 ...
│ │ └ <classmethod(<function APIError.raise_for_async_response at 0x7fac68a14680>)>
│ └ <class 'google.genai.errors.APIError'>
└ <module 'google.genai.errors' from '/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/errors.py'>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/errors.py", line 216, in raise_for_async_response
await cls.raise_error_async(status_code, response_json, response)
│ │ │ │ └ <ClientResponse(https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse) [400 ...
│ │ │ └ {'message': '{\n "error": {\n "code": 400,\n "message": "* GenerateContentRequest.tools[0].function_declarations[9].pa...
│ │ └ 400
│ └ <classmethod(<function APIError.raise_error_async at 0x7fac68a147c0>)>
└ <class 'google.genai.errors.APIError'>
File "/home/saite/project/AstrBot/.venv/lib/python3.12/site-packages/google/genai/errors.py", line 238, in raise_error_async
raise ClientError(status_code, response_json, response)
│ │ │ └ <ClientResponse(https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse) [400 ...
│ │ └ {'message': '{\n "error": {\n "code": 400,\n "message": "* GenerateContentRequest.tools[0].function_declarations[9].pa...
│ └ 400
└ <class 'google.genai.errors.ClientError'>
google.genai.errors.ClientError: 400 Bad Request. {'message': '{\n "error": {\n "code": 400,\n "message": "* GenerateContentRequest.tools[0].function_declarations[9].parameters.properties[payload].any_of[1].items: missing field.\\n",\n "status": "INVALID_ARGUMENT"\n }\n}\n', 'status': 'Bad Request'}
[21:44:02.449] [Core] [INFO] [result_decorate.stage:189]: 流式输出已启用,跳过结果装饰阶段
[21:44:26.088] [Core] [INFO] [routes.config:307]: Saving config, is_core=True
What happened / 发生了什么
astrbot/core/computer/tools/neo_skills.py中定义了CreateSkillPayloadTool工具,其参数定义如下:{ "type": "object", "properties": { "payload": { "anyOf": [{"type": "object"}, {"type": "array"}], "description": ( "Skill payload JSON. Typical schema: {skill_markdown, inputs, outputs, meta}. " "This only stores content and returns payload_ref; it does not create a candidate or release." ), }, "kind": { "type": "string", "description": "Payload kind.", "default": "astrbot_skill_v1", }, }, "required": ["payload"], }注意
payload参数,代码定义其类型可为object或array,但对于array时的情况,其并未定义items属性指定数组的元素类型。在使用Gemini API时,上述行为会导致错误:
对应的传递给Google GenAI库的工具调用参数如下:
{ "name": "astrbot_create_skill_payload", "description": "Step 1/3 for Neo skill authoring: create immutable payload content and return payload_ref. Use this to store skill_markdown and structured metadata; do NOT write local skill folders directly.", "parameters": { "type": "object", "required": [ "payload" ], "properties": { "payload": { "anyOf": [ { "type": "object" }, { "type": "array" } ] }, "kind": { "type": "string", "description": "Payload kind." } } } }根据报错信息,可知Gemini API期望
payload的array变体含有items字段。查阅Gemini API文档12,可知
items字段的定义如下:其指定了当
type为array时,数组元素的基本类型。虽然文档中标注为"Optional",但在type为array时,API 似乎要求必须指定该参数。CreateSkillPayloadTool的功能由shipyard/shipyard-neo实现,其对应shipyard-neo的"5.1.1 创建 payload" API3:请求体:
payloadkind"generic"响应
201:{ "payload_ref": "blob:blob_abc123", "kind": "candidate_payload" }其中并未明确指定
array的元素类型,但根据其实现的功能,似乎可以认为元素可以为任意object?故可考虑设定items字段为:Reproduce / 如何复现?
测试版本:v4.20.0 (a8ff2b3d9cb3f340def8b754854ceb0642a52a0d)
google_gemini/gemini-2.5-flash/google_gemini/gemini-3.1-pro-preview模型AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
uv run main.py)OS
Linux
Logs / 报错日志
Are you willing to submit a PR? / 你愿意提交 PR 吗?
Code of Conduct
Footnotes
https://ai.google.dev/gemini-api/docs/function-calling?example=meeting#function-declarations ↩
https://ai.google.dev/api/caching#Schema ↩
https://github.com/AstrBotDevs/shipyard-neo/blob/main/doc/bay_api_v1.md#5-skills-api%E6%8A%80%E8%83%BD%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F ↩