sigoden/aichat · error

Invalid messages

Error message

Invalid messages

What it means

parse_messages rejects the request when 'tool_results' were set (i.e. messages contained tool/role content) but the message sequence is not a valid tool-call continuation. The OpenAI-compatible endpoint requires tool result messages to follow a corresponding assistant tool_calls message.

Solutions

  1. Ensure every tool message is immediately preceded by an assistant message with tool_calls
  2. Include the full conversation history from the assistant tool_calls turn onward
  3. Match each tool message's tool_call_id to one of the assistant's tool_calls
  4. If sending results without a tool call, send them as user/assistant content instead

Example fix

// before: tool result without the assistant tool_calls turn
{"messages":[{"role":"tool","tool_call_id":"x","content":"42"}]}
// after: include the assistant turn first
{"messages":[{"role":"assistant","tool_calls":[{"id":"x",...}]},{"role":"tool","tool_call_id":"x","content":"42"}]}
Defensive patterns

Strategy: validation

Validate before calling

function validateToolFlow(messages) {
  for (let i = 0; i < messages.length; i++) {
    const m = messages[i];
    if (m.role === 'tool') {
      const prev = messages[i - 1];
      if (!prev || prev.role !== 'assistant' || !prev.tool_calls) {
        throw new Error(`tool message at ${i} has no preceding assistant tool_calls`);
      }
    }
  }
}

Prevention

When it happens

Trigger: POST /v1/chat/completions with a messages array where a tool message appears without a preceding assistant message containing tool_calls, or tool results are present in a malformed conversation shape.

Common situations: Clients replaying tool outputs after truncating the assistant tool_calls message; hand-built request bodies missing the assistant turn; agent loops that drop intermediate messages.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09). Data as JSON: /api/errors/8692848dc1002860. Report an issue: GitHub.

Appendix: source

Thrown at src/serve.rs:910

                        output.push(Message::new(
                            MessageRole::Assistant,
                            MessageContent::ToolCalls(MessageContentToolCalls::new(list, text)),
                        ));
                        tool_results = None;
                    } else {
                        tool_results = Some((text, tool_calls, tool_values));
                    }
                }
                None => return Err(err()),
            },
            _ => {
                return Err(err());
            }
        }
    }

    if tool_results.is_some() {
        bail!("Invalid messages");
    }

    Ok(output)
}

fn parse_tools(tools: Option<Vec<Value>>) -> Result<Option<Vec<FunctionDeclaration>>> {
    let tools = match tools {
        Some(v) => v,
        None => return Ok(None),
    };
    let mut functions = vec![];
    for (i, tool) in tools.into_iter().enumerate() {
        if let (Some("function"), Some(function)) = (
            tool["type"].as_str(),
            tool["function"]
                .as_object()
                .and_then(|v| serde_json::from_value(json!(v)).ok()),
        ) {

View on GitHub (pinned to 82976d349a)