Billionmail/BillionMail · warning
Chat not found or already stopped
Error message
Chat not found or already stopped
What it means
Stop() looks up the chat ID in the in-process ChatStatus map; if the ID is absent it means the chat was never started (or its entry was removed) or it was already stopped. The library throws this sentinel error to reject stopping a non-active chat instead of silently mutating the map.
Source
Thrown at core/internal/service/askai/chat.go:303
// RemoveChat removes a chat by its ID
// This function should handle the logic for removing a chat based on the provided chat ID
func RemoveChat(chatId string) error {
chatPath := CHAT_CONFIG_PATH + "/" + chatId
if !public.FileExists(chatPath) {
return os.ErrNotExist
}
err := os.RemoveAll(chatPath)
if err != nil {
return err
}
return nil
}
func Stop(chatId string) error {
// Implementation for stopping a chat
// This function should handle the logic for stopping a chat based on the provided parameters
if _, exists := ChatStatus[chatId]; !exists {
return errors.New("Chat not found or already stopped")
}
ChatStatus[chatId] = false // Set chat status to inactive
return nil
}
// GetLastUsage retrieves the last usage statistics for a chat by its ID
// This function should handle the logic for loading the last usage statistics of a chat based on the provided chat ID
func GetLastUsage(chatId string) ChatUsage {
messages := GetMessages(chatId)
if len(messages) == 0 {
return ChatUsage{}
}
lastMessage := messages[len(messages)-1]
return lastMessage.Usage
}
// GetHtml retrieves the HTML content of a chat by its ID
// This function should handle the logic for loading the HTML content of a chat based on the provided chat IDView on GitHub (pinned to fc36c76c05)
Solutions
- Check chat existence first (e.g. a ChatExists helper or reading ChatStatus) before calling Stop
- Treat this error as an idempotent success in the caller: the desired end state (chat stopped) is already reached
- Ensure the same instance that started the chat handles Stop (sticky sessions/shared state) since ChatStatus is process-local
- Verify the chatId passed is the exact ID returned when the chat was created
Example fix
// before
if err := askai.Stop(chatId); err != nil {
return err
}
// after
if err := askai.Stop(chatId); err != nil {
if err.Error() == "Chat not found or already stopped" {
return nil // already stopped; idempotent
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
func chatIsActive(chatId string) bool {
askai.ChatStatusMu.Lock()
defer askai.ChatStatusMu.Unlock()
active, ok := askai.ChatStatus[chatId]
return ok && active
}
// call Stop only if chatIsActive(chatId) Try / catch
if err := askai.Stop(chatId); err != nil {
if strings.Contains(err.Error(), "not found or already stopped") {
return nil // idempotent: already in desired state
}
return err
} Prevention
- Track chat IDs client-side and disable the stop control once a stream completes
- Treat Stop as idempotent — never surface this error to end users
- Remember ChatStatus is in-memory; use sticky routing or shared state across replicas
- Never reuse or guess chat IDs; always use the ID returned at chat creation
When it happens
Trigger: Calling askai.Stop(chatId) with an ID that was never registered in ChatStatus (chat never started), an ID that was already stopped (entry removed on completion), a stale ID after process restart (ChatStatus is in-memory only), or a typo'd/foreign chat ID.
Common situations: Double-clicking a 'stop' button so Stop fires twice; a frontend retrying Stop after the stream already finished; a server restart wiping the in-memory map while clients still hold old chat IDs; load-balanced deployments where the chat lives on another instance.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- DNS automated resolution failed: ClientID, ClientSecret or T
- DNS automated resolution failed: APIKey or APISecret is empt
- Failed to get configuration
- Failed to create ACME client: {}
- Chat not found
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/c1df052eed4d8e14.
Report an issue: GitHub.