wavetermdev/waveterm · error

function call with callId %s not found in chat %s

Error message

function call with callId %s not found in chat %s

What it means

UpdateToolUseData scanned all OpenAIChatMessage entries in the chat's NativeMessages and found no FunctionCall whose CallId matches the given callId, at openai-backend.go:439. The chat exists but the specific tool-call item does not.

Source

Thrown at pkg/aiusechat/openai/openai-backend.go:439

		}

		if chatMsg.FunctionCall != nil && chatMsg.FunctionCall.CallId == callId {
			updatedMsg := *chatMsg
			updatedFunctionCall := *chatMsg.FunctionCall
			updatedFunctionCall.ToolUseData = &newToolUseData
			updatedMsg.FunctionCall = &updatedFunctionCall

			aiOpts := &uctypes.AIOptsType{
				APIType:    chat.APIType,
				Model:      chat.Model,
				APIVersion: chat.APIVersion,
			}

			return chatstore.DefaultChatStore.PostMessage(chatId, aiOpts, &updatedMsg)
		}
	}

	return fmt.Errorf("function call with callId %s not found in chat %s", callId, chatId)
}

func RemoveToolUseCall(chatId string, callId string) error {
	chat := chatstore.DefaultChatStore.Get(chatId)
	if chat == nil {
		return fmt.Errorf("chat not found: %s", chatId)
	}

	for _, genMsg := range chat.NativeMessages {
		chatMsg, ok := genMsg.(*OpenAIChatMessage)
		if !ok {
			continue
		}

		if chatMsg.FunctionCall != nil && chatMsg.FunctionCall.CallId == callId {
			chatstore.DefaultChatStore.RemoveMessage(chatId, chatMsg.MessageId)
			return nil
		}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Confirm the callId came from the current chat's streaming response (match FunctionCall.CallId)
  2. Check the chat still contains the function-call message: enumerate chat.NativeMessages and search for the callId before updating
  3. Treat this as terminal for that callId: skip the update or re-post the tool output as a new message instead of retrying
  4. Ensure you are using the callId (tool_call id from the model), not the message/item id

Example fix

// before
err := UpdateToolUseData(chatId, callId, toolData) // panics on not-found
// after
if err := UpdateToolUseData(chatId, callId, toolData); err != nil {
    log.Printf("skip tool update (call gone): %v", err)
    return nil // do not retry
}
Defensive patterns

Strategy: validation

Validate before calling

chat := chatstore.DefaultChatStore.Get(chatId)
if chat != nil {
    found := false
    for _, m := range chat.NativeMessages {
        if cm, ok := m.(*OpenAIChatMessage); ok && cm.FunctionCall != nil && cm.FunctionCall.CallId == callId {
            found = true
            break
        }
    }
    if !found {
        return nil // callId no longer present; skip update
    }
}

Type guard

func findFunctionCall(chatId, callId string) *OpenAIChatMessage {
    chat := chatstore.DefaultChatStore.Get(chatId)
    if chat == nil {
        return nil
    }
    for _, m := range chat.NativeMessages {
        if cm, ok := m.(*OpenAIChatMessage); ok && cm.FunctionCall != nil && cm.FunctionCall.CallId == callId {
            return cm
        }
    }
    return nil
}

Try / catch

if err := UpdateToolUseData(chatId, callId, data); err != nil {
    if strings.Contains(err.Error(), "not found in chat") {
        log.Printf("tool call %s gone; dropping update", callId)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling UpdateToolUseData with a callId that was never issued in this chat, a callId belonging to another chat, a callId already removed via RemoveToolUseCall, or a callId whose message is stored as a non-OpenAI message (skipped via the ok-continue path).

Common situations: Tool result arrives after the call was cancelled/deleted; retrying an update after a first attempt already removed the message; ids mixed across concurrent chats; backend restarted losing in-flight call records.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/f044cbab93c70d39. Report an issue: GitHub.