---
source_url: https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/messages/threads
title: Message threads
updated_at: 2026-06-16T12:48:54.621Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Message threads

Organize conversations into threads for topic-specific discussions.

Benefits:

* Focus discussions on specific topics
* Clarify and resolve issues without cross-talk
* Keep main channel conversations clean

Thread channels have IDs starting with `PUBNUB_INTERNAL_THREAD_{channel_id}_{message_id}`. Messages with threads have `hasThread: true`.

[ThreadMessage](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/thread-message) and [ThreadChannel](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/thread-channel) extend the base `Message` and `Channel` entities with thread-specific methods.

## Create thread

`createThread(text:params:)` creates a thread (channel) for a selected message and sends the first thread message in a single call. It returns both the thread channel and the updated parent message.

:::note Deprecation
Both `createThread()` (no parameters) and `createThread(text:meta:shouldStore:usePost:ttl:quotedMessage:files:usersToMention:customPushData:)` are deprecated. Use `createThread(text:params:)` instead.
:::

### Method signature

This method has the following signature:

```swift
message.createThread(
    text: String,
    params: SendTextParams = SendTextParams()
) async throws -> CreateThreadResult<ThreadChannelImpl, MessageImpl>
```

The `CreateThreadResult` struct contains:

```swift
public struct CreateThreadResult<TC: ThreadChannel, M: Message> {
    public let threadChannel: TC
    public let parentMessage: M
}
```

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| text | String | Yes |  | Text of the first message in the thread. |
| params | SendTextParams | Optional | `SendTextParams()` | Publishing options grouped in a single struct. See [sendText()](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/messages/send-receive#method-signature) for field descriptions. |

#### Output

| Parameter | Description |
| --- | --- |
| `CreateThreadResult`Type: `CreateThreadResult<ThreadChannelImpl, MessageImpl>` | Object containing the thread channel and the updated parent message with `hasThread: true`. |
| → `threadChannel`Type: `ThreadChannelImpl` | The newly created thread channel. |
| → `parentMessage`Type: `MessageImpl` | The parent message updated with thread metadata. |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Create a thread for a message on the `support` channel with an initial reply.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    let timetoken: Timetoken = 16200000000000001
    if let message = try await channel.getMessage(timetoken: timetoken) {
      // Create a thread by sending the first reply
      let result = try await message.createThread(text: "Starting a thread on this topic")
      debugPrint("Thread created successfully with ID: \(result.threadChannel.id)")
      debugPrint("Parent channel ID: \(result.threadChannel.parentChannelId)")
      debugPrint("Updated parent message: \(result.parentMessage.hasThread)")
    } else {
      debugPrint("No message found with this timetoken")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

## Send thread message

Reply to a message in a thread by calling the `sendText()` method from the previously created `ThreadChannel` object.

### Method signature

Head over to the [sendText() method](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/messages/send-receive) section for details.

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Send a message in a thread created for the last message on the `support` channel.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    let timetoken: Timetoken = 16200000000000001
    if let message = try await channel.getMessage(timetoken: timetoken) {
      let threadChannel = try await message.getThread()
      let replyInThreadTimetoken = try await threadChannel.sendText(text: "Good job, guys!")
      debugPrint("Reply in a thread successfuly sent at \(replyInThreadTimetoken)")
    } else {
      debugPrint("No message found with this timetoken")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

## Get thread

Get the thread channel on which the thread message is published.

### Method signature

This method has the following signature:

```swift
message.getThread() async throws -> ThreadChannelImpl
```

#### Input

This method doesn't take any parameters.

#### Output

| Type | Description |
| --- | --- |
| `ThreadChannelImpl` | Object returning the thread channel metadata. |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Get the thread channel created from the message with the `16200000000000001` timetoken.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    let timetoken: Timetoken = 16200000000000001
    if let message = try await channel.getMessage(timetoken: timetoken) {
      let threadChannel = try await message.getThread()
      debugPrint("Thread channel ID: \(threadChannel.id)")
      debugPrint("Parent channel ID: \(threadChannel.parentChannelId)")
    } else {
      debugPrint("No message found with this timetoken")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

## Check if message starts thread

`hasThread` indicates if a message starts a thread.

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Check if the message with the `16200000000000001` timetoken starts a thread.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    let timetoken: Timetoken = 16200000000000001
    if let message = try await channel.getMessage(timetoken: timetoken) {
      debugPrint("Message fetched successfully: \(message.text)")
      debugPrint("Does this message have a thread: \(message.hasThread)")
    } else {
      debugPrint("No message found with this timetoken")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

## Get thread message updates

`streamUpdatesOn()` on `ThreadMessage` receives updates when thread messages or [reactions](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/messages/reactions) change.

The callback fires whenever messages are added, edited, deleted, or reactions change. Returns an asynchronous stream.

:::note Stream update behavior
`streamUpdatesOn()` returns the complete list of monitored thread messages on each change.
:::

### Method signature

This method takes the following parameters:

```swift
ThreadMessageImpl.streamUpdatesOn(messages: [ThreadMessageImpl]) -> AsyncStream<[ThreadMessageImpl]>
```

#### Input

| Parameter | Description |
| --- | --- |
| `messages` *Type: `[ThreadMessageImpl]`Default: n/a | Collection of [ThreadMessageImpl objects](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/thread-message) for which you want to get updates on changed message threads or related message reactions. |

#### Output

| Parameter | Description |
| --- | --- |
| `AsyncStream<[ThreadMessageImpl]>` | An asynchronous stream that produces updates when any item in the `messages` collection is updated. |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Get message threads and message reaction-related updates for the first page of messages published in a thread on the `support` channel.

###### AsyncStream

```swift
// Assumes a "ThreadChannelImpl" reference named "threadChannel"
Task {
  if let threadMessage = try await threadChannel.getHistory(count: 1).messages.first {
    for await receivedThreadMessages in ThreadMessageImpl.streamUpdatesOn(messages: [threadMessage]) {
      // The stream returns the complete list of all thread messages you're monitoring
      // (including all reactions) each time any change occurs.
      debugPrint("Received elements: \(receivedThreadMessages)")
    }
  } else {
    debugPrint("Message not found")
  }
}
```

###### Closure

```swift
// Assumes a "ThreadMessageImpl" reference named "threadMessage"
  
// Important: Keep a strong reference to the returned "AutoCloseable" object as long as you want
// to receive updates. If the "AutoCloseable" is deallocated, the stream will be cancelled,
// and no further items will be produced. You can also stop receiving updates manually
// by calling the "close()" method on the "AutoCloseable" object.
autoCloseable = ThreadMessageImpl.streamUpdatesOn(messages: [threadMessage]) { updatedThreadMessages in
  // The closure receives the complete list of all thread messages you're monitoring
  // (including all reactions) each time any change occurs.
  updatedThreadMessages.forEach { updatedThreadMessage in
    debugPrint("-=Updated thread message: \(updatedThreadMessage)")
  }
}
```

## Get thread channel updates

`streamUpdatesOn()` on `ThreadChannel` receives updates when thread channels are edited or removed.

The callback fires whenever channel metadata changes. Returns an asynchronous stream.

:::note Stream update behavior
`streamUpdatesOn()` returns the complete list of monitored thread channels on each change.
:::

### Method signature

This method takes the following parameters:

```swift
ThreadChannelImpl.streamUpdatesOn(
    channels: [ThreadChannelImpl],
) -> AsyncStream<[ThreadChannelImpl]>
```

#### Input

| Parameter | Description |
| --- | --- |
| `channels` *Type: `[ThreadChannelImpl]`Default: n/a | Array of [ThreadChannelImpl objects](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/channel) for which you want to get updates on changed channel threads. |

#### Output

| Parameter | Description |
| --- | --- |
| `AsyncStream<[ThreadChannelImpl]>` | An asynchronous stream that produces updates when any item in the `channels` collection is updated. |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

###### AsyncStream

```swift
// Assumes two "ThreadChannelImpl" references named "threadChannel" and "anotherThreadChannel"
Task {
  for await updatedThreadChannels in ThreadChannelImpl.streamUpdatesOn(channels: [threadChannel, anotherThreadChannel]) {
    // The stream returns the complete list of all thread channels you're monitoring
    // each time any change occurs.
    debugPrint("Updated thread channels: \(updatedThreadChannels)")
  }
}
```

###### Closure

```swift
// Assumes an array of "ThreadChannelImpl" objects named "threadChannels"
  
// Important: Keep a strong reference to the returned "AutoCloseable" object as long as you want
// to receive new updates. If the "AutoCloseable" is deallocated, the stream will be cancelled,
// and no further items will be produced. You can also stop receiving updates manually
// by calling the "close()" method on the "AutoCloseable" object.
autoCloseable = ThreadChannelImpl.streamUpdatesOn(channels: threadChannels) { updatedThreadChannels in
  // The closure receives the complete list of all thread channels you're monitoring
  // each time any change occurs.
  updatedThreadChannels.forEach { updatedThreadChannel in
    debugPrint("Updated thread channel: \(updatedThreadChannel)")
  }
}
```

## Get historical thread message

`getHistory()` on `ThreadChannel` fetches historical thread messages.

### Method signature

This method takes the following parameters:

```swift
threadChannel.getHistory(
    startTimetoken: Timetoken? = nil,
    endTimetoken: Timetoken? = nil,
    count: Int = 25
  ) async throws -> (messages: [ThreadMessageImpl], isMore: Bool)
```

#### Input

| Parameter | Description |
| --- | --- |
| `startTimetoken`Type: `Timetoken`Default: n/a | [Timetoken](https://www.pubnub.com/docs/sdks/swift/api-reference/misc#time) delimiting the start of a time slice (exclusive) to pull thread messages from. For details, refer to the [Fetch History section](https://www.pubnub.com/docs/sdks/swift/api-reference/storage-and-playback#fetch-history). |
| `endTimetoken`Type: `Timetoken`Default: n/a | Timetoken delimiting the end of a time slice (inclusive) to pull thread messages from. For details, refer to the [Fetch History section](https://www.pubnub.com/docs/sdks/swift/api-reference/storage-and-playback#fetch-history). |
| `count`Type: `Int`Default: `25` | Number of historical thread messages to return for the channel in a single call. Since each call returns all attached message reactions by default, the maximum number of returned thread messages is `25`. For more details, refer to the description of the `includeMessageActions` parameter in the [Swift SDK docs](https://www.pubnub.com/docs/sdks/swift/api-reference/storage-and-playback#methods). |

#### Output

| Parameter | Description |
| --- | --- |
| `(messages: [ThreadMessageImpl], isMore: Bool)`Type: `object` | A tuple containing a list of `ThreadMessageImpl` objects and a boolean flag indicating if there are more messages available. |

By default, each call returns all message reactions and metadata attached to the retrieved thread messages.

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Fetch `10` historical thread messages that are older than the timetoken `15343325214676133`.

```swift
// Assumes a "ThreadChannelImpl" reference named "threadChannel"
Task {
  let response = try await threadChannel.getHistory(
    startTimetoken: 15343325214676133,
    count: 10
  )
  response.messages.forEach { message in
    debugPrint("Thread message: \(message.channelId) - \(message.text)")
  }
    
  let theOldestTimetoken = response.messages.compactMap { $0.timetoken }.min()
    
  if let theOldestTimetoken, !response.messages.isEmpty && response.isMore {
    let nextHistoryResults = try await threadChannel.getHistory(startTimetoken: theOldestTimetoken, count: 10)
  }
}
```

## Remove thread

`removeThread()` removes a thread (channel) for a selected message.

### Method signature

This method has the following signature:

```swift
message.removeThread() async throws
```

#### Input

This method doesn't take any parameters.

#### Output

| Parameter | Description |
| --- | --- |
| `ChannelImpl?` | The updated channel object after the removal of the thread, or `nil` if no channel was returned. |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Remove a thread for the last message on the `support` channel.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    if let message = try await channel.getHistory(count: 1).messages.first {
      let updatedChannel = try await message.removeThread()
      debugPrint("Thread removed successfully.")
      debugPrint("Updated Channel: \(String(describing: updatedChannel))")
    } else {
      debugPrint("Message not found")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

## Pin thread message to thread channel

`pinMessage()` on `ThreadChannel` pins a thread message to the thread channel.

### Method signature

This method takes the following parameters:

```swift
threadChannel.pinMessage(
    message: ThreadMessageImpl
) async throws -> ThreadChannelImpl
```

#### Input

| Parameter | Description |
| --- | --- |
| `message` *Type: `ThreadMessageImpl`Default: n/a | [ThreadMessageImpl object](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/thread-message) you want to pin to the selected thread channel. |

#### Output

| Parameter | Description |
| --- | --- |
| `ThreadChannelImpl` | Object returning the thread channel metadata updated with these custom fields: `pinnedMessageTimetoken` to mark the timetoken when the message was pinned `pinnedMessageChannelID` to mark the channel on which the message was pinned to the thread channel (unpinning was performed either directly on the parent channel or on a thread channel). |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

A thread was created for the last message in the `support` parent channel. Pin the last message from this thread to the thread channel.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    // Get the last message on the channel, which is the root message for the thread
    if let message = try await channel.getHistory(count: 1).messages.first {
      // Get the thread channel
      let threadChannel = try await message.getThread()
      // Get the last message on the thread channel
      if let threadMessage = try await threadChannel.getHistory(count: 1).messages.first {
        // Pin the message from the thread to the thread channel
        let updatedChannel = try await threadChannel.pinMessage(message: threadMessage)
        // Prints the updated channel object
        debugPrint("Updated channel object: \(updatedChannel)")
      } else {
        debugPrint("No messages found in the thread channel.")
      }
    } else {
      debugPrint("Message not found")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

## Pin thread message to parent channel

`pinMessageToParentChannel()` (on `ThreadChannel`) and `pinToParentChannel()` (on `ThreadMessage`) pin a thread message to the parent channel.

### Method signature

These methods take the following parameters:

* pinMessageToParentChannel() (on the ThreadChannel object) 1threadChannel.pinMessageToParentChannel(2 message: ThreadMessageImpl3) async throws -> ChannelImpl
* pinToParentChannel() (on the ThreadMessage object) 1threadMessage.pinToParentChannel() async throws -> ChannelImpl

#### Input

| Parameter | Required in `pinMessageToParentChannel()` | Required in `pinToParentChannel()` | Description |
| --- | --- | --- | --- |
| `message`Type: `ThreadMessageImpl`Default: n/a | Yes | No | [ThreadMessageImpl object](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/thread-message) you want to pin to the selected parent channel. |

#### Output

| Parameter | Description |
| --- | --- |
| `ChannelImpl` | Object returning the channel metadata updated with these custom fields: `pinnedMessageTimetoken` to mark the timetoken when the message was pinned `pinnedMessageChannelID` to mark the channel on which the message was pinned to the parent channel (pinning was performed either directly on the parent channel or on a thread channel). |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

A thread was created for the last message in the `support` parent channel. Pin the last message from this thread to the parent channel.

* pinMessageToParentChannel() // Assuming you have a reference of type "ChatImpl" named "chat" Task { if let channel = try await chat.getChannel(channelId: "support") { // Get the last message on the channel, which is the root message for the thread if let message = try await channel.getHistory(count: 1).messages.first { // Get the thread channel let threadChannel = try await message.getThread() // Get the last message on the thread channel if let threadMessage = try await threadChannel.getHistory(count: 1).messages.first { // Pin the message to the parent channel let updatedChannel = try await threadChannel.pinMessageToParentChannel(message: threadMessage) debugPrint("Message pinned successfully to the parent channel") debugPrint("Updated channel object: \(updatedChannel)") } else { debugPrint("No messages found in the thread channel") } } else { debugPrint("Message not found") } } else { debugPrint("Channel not found") } }
* pinToParentChannel() // Assuming you have a reference of type "ChatImpl" named "chat" Task { if let channel = try await chat.getChannel(channelId: "support") { // Get the last message on the channel, which is the root message for the thread if let message = try await channel.getHistory(count: 1).messages.first { // Get the thread channel let threadChannel = try await message.getThread() // Get the last message on the thread channel if let threadMessage = try await threadChannel.getHistory(count: 1).messages.first { // Pin the message to the parent channel let updatedChannel = try await threadMessage.pinToParentChannel() debugPrint("Message pinned successfully to the parent channel") debugPrint("Updated channel object: \(updatedChannel)") } else { debugPrint("No messages found in the thread channel") } } else { debugPrint("Message not found") } } else { debugPrint("Channel not found") } }

## Unpin thread message from thread channel

`unpinMessage()` on `ThreadChannel` unpins the pinned thread message.

### Method signature

This method has the following signature:

```swift
threadChannel.unpinMessage() async throws -> ThreadChannelImpl
```

#### Input

This method doesn't take any parameters.

#### Output

| Parameter | Description |
| --- | --- |
| `ThreadChannelImpl` | Object returning the thread channel metadata updated with these custom fields: `pinnedMessageTimetoken` to mark the timetoken when the message was unpinned `pinnedMessageChannelID` to mark the channel on which the message was unpinned from the thread channel (unpinning was performed either directly on the parent channel or on a thread channel). |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Unpin the thread message from the thread (channel) created for the last message on the `support` channel.

```swift
// Assuming you have a reference of type "ChatImpl" named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    // Get the last message on the channel, which is the root message for the thread
    if let message = try await channel.getHistory(count: 1).messages.first {
      // Get the thread channel
      let threadChannel = try await message.getThread()
      // Get the last message on the thread channel
      if let threadMessage = try await threadChannel.getHistory(count: 1).messages.first {
        let updatedChannel = try await threadChannel.unpinMessage()
        debugPrint("Message unpinned successfully from the thread channel")
        debugPrint("Updated channel object: \(updatedChannel)")
      } else {
        debugPrint("No messages found in the thread channel.")
      }
    } else {
      debugPrint("Message not found")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

## Unpin thread message from parent channel

`unpinMessageFromParentChannel()` (on `ThreadChannel`) and `unpinFromParentChannel()` (on `ThreadMessage`) unpin a thread message from the parent channel.

### Method signature

These methods have the following signatures:

* unpinMessageFromParentChannel() (on the ThreadChannel object) 1threadChannel.unpinMessageFromParentChannel() async throws -> ChannelImpl
* unpinFromParentChannel() (on the ThreadMessage object) 1threadMessage.unpinFromParentChannel() async throws -> ChannelImpl

#### Input

These methods don't take any parameters.

#### Output

| Parameter | Description |
| --- | --- |
| `ChannelImpl` | Object returning the channel metadata updated with these custom fields: `pinnedMessageTimetoken` to mark the timetoken when the message was unpinned `pinnedMessageChannelID` to mark the channel on which the message was unpinned from the parent channel (unpinning was performed either directly on the parent channel or on a thread channel). |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Unpin the thread message from the `support` parent channel.

* unpinMessageFromParentChannel() // Assuming you have a reference of type "ChatImpl" named "chat" Task { if let channel = try await chat.getChannel(channelId: "support") { // Get the last message on the channel, which is the root message for the thread if let message = try await channel.getHistory(count: 1).messages.first { // Get the thread channel let threadChannel = try await message.getThread() // Get the last message on the thread channel if let threadMessage = try await threadChannel.getHistory(count: 1).messages.first { let updatedChannel = try await threadChannel.unpinMessageFromParentChannel() debugPrint("Message unpinned successfully from the parent channel") debugPrint("Updated channel object: \(updatedChannel)") } else { debugPrint("No messages found in the thread channel") } } else { debugPrint("Message not found") } } else { debugPrint("Channel not found") } }
* unpinFromParentChannel() // Assuming you have a reference of type "ChatImpl" named "chat" Task { if let channel = try await chat.getChannel(channelId: "support") { // Get the last message on the channel, which is the root message for the thread if let message = try await channel.getHistory(count: 1).messages.first { // Get the thread channel let threadChannel = try await message.getThread() // Get the last message on the thread channel if let threadMessage = try await threadChannel.getHistory(count: 1).messages.first { let updatedChannel = try await threadMessage.unpinFromParentChannel() debugPrint("Message unpinned successfully from the parent channel") debugPrint("Updated channel object: \(updatedChannel)") } else { debugPrint("No messages found in the thread channel") } } else { debugPrint("Message not found") } } else { debugPrint("Channel not found") } }