diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt
index 56867c3ba..c2770bee5 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt
@@ -38,10 +38,10 @@ private val UNSUPPORTED_FLASH_MESSAGE_PLAIN = PlainText("[闪照]请使用新版
 @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
 @OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class)
 internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: Boolean): MutableList<ImMsgBody.Elem> {
-    val elements = mutableListOf<ImMsgBody.Elem>()
+    val elements = ArrayList<ImMsgBody.Elem>(this.size)
 
     if (this.anyIsInstance<QuoteReply>()) {
-        when (val source = this[QuoteReply].source) {
+        when (val source = this[QuoteReply]!!.source) {
             is MessageSourceInternal -> elements.add(ImMsgBody.Elem(srcMsg = source.toJceData()))
             else -> error("unsupported MessageSource implementation: ${source::class.simpleName}. Don't implement your own MessageSource.")
         }
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessageEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessageEvent.kt
index 27d0a52d7..e73100916 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessageEvent.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessageEvent.kt
@@ -32,7 +32,7 @@ class FriendMessageEvent constructor(
 ) : @PlannedRemoval("1.2.0") FriendMessage(), BroadcastControllable {
     init {
         val source =
-            message.getOrNull(MessageSource) ?: throw IllegalArgumentException("Cannot find MessageSource from message")
+            message[MessageSource] ?: throw IllegalArgumentException("Cannot find MessageSource from message")
         check(source is OnlineMessageSource.Incoming.FromFriend) { "source provided to a FriendMessage must be an instance of OnlineMessageSource.Incoming.FromFriend" }
     }
 
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessageEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessageEvent.kt
index 5ff44d665..d73a0ed0c 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessageEvent.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessageEvent.kt
@@ -35,7 +35,7 @@ class GroupMessageEvent(
     override val time: Int
 ) : @PlannedRemoval("1.2.0") GroupMessage(), Event {
     init {
-        val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message")
+        val source = message[MessageSource] ?: error("Cannot find MessageSource from message")
         check(source is OnlineMessageSource.Incoming.FromGroup) { "source provided to a GroupMessage must be an instance of OnlineMessageSource.Incoming.FromGroup" }
     }
 
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageEvent.kt
index 775affd92..707f281ef 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageEvent.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageEvent.kt
@@ -135,11 +135,6 @@ interface MessageEventExtensions<out TSender : User, out TSubject : Contact> :
     @JvmSynthetic
     suspend inline fun quoteReply(plain: String): MessageReceipt<TSubject> = reply(this.message.quote() + plain)
 
-    @JvmSynthetic
-    inline operator fun <M : Message> get(at: Message.Key<M>): M {
-        return this.message[at]
-    }
-
     @JvmSynthetic
     inline fun At.isBot(): Boolean = target == bot.id
 
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/TempMessageEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/TempMessageEvent.kt
index 8455479e1..a68fb329f 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/TempMessageEvent.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/TempMessageEvent.kt
@@ -23,7 +23,7 @@ class TempMessageEvent(
     override val time: Int
 ) : TempMessage(), BroadcastControllable {
     init {
-        val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message")
+        val source = message[MessageSource] ?: error("Cannot find MessageSource from message")
         check(source is OnlineMessageSource.Incoming.FromTemp) { "source provided to a TempMessage must be an instance of OnlineMessageSource.Incoming.FromTemp" }
     }
 
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
index c92f3868b..50ddacf0b 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
@@ -20,6 +20,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
 import kotlin.js.JsName
 import kotlin.jvm.JvmMultifileClass
 import kotlin.jvm.JvmName
+import kotlin.jvm.JvmOverloads
 import kotlin.jvm.JvmSynthetic
 import kotlin.reflect.KProperty
 
@@ -46,23 +47,13 @@ interface MessageChain : Message, Iterable<SingleMessage> {
     val size: Int
 
     /**
-     * 获取第一个类型为 [key] 的 [Message] 实例
+     * 获取第一个类型为 [key] 的 [Message] 实例. 若不存在此实例, 返回 `null`
      *
      * @param key 由各个类型消息的伴生对象持有. 如 [PlainText.Key]
-     * @throws NoSuchElementException 当找不到这个类型的 [Message] 时
      */
     @Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION", "INAPPLICABLE_JVM_NAME")
     @JvmName("first")
-    final operator fun <M : Message> get(key: Message.Key<M>): M = first(key)
-
-    /**
-     * 获取第一个类型为 [key] 的 [Message] 实例, 找不到则返回 `null`
-     *
-     * @param key 由各个类型消息的伴生对象持有. 如 [PlainText.Key]
-     */
-    @Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION", "INAPPLICABLE_JVM_NAME")
-    @JvmName("firstOrNull")
-    final fun <M : Message> getOrNull(key: Message.Key<M>): M? = firstOrNull(key)
+    final operator fun <M : Message> get(key: Message.Key<M>): M? = firstOrNull(key)
 
     /**
      * 遍历每一个有内容的消息, 即 [At], [AtAll], [PlainText], [Image], [Face] 等
@@ -87,10 +78,33 @@ interface MessageChain : Message, Iterable<SingleMessage> {
     final fun __forEachForJava__(block: (Message) -> Unit) {
         this.forEach(block)
     }
+
+
+    /**
+     * 获取第一个类型为 [key] 的 [Message] 实例, 找不到则返回 `null`
+     *
+     * @param key 由各个类型消息的伴生对象持有. 如 [PlainText.Key]
+     */
+    @Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION", "INAPPLICABLE_JVM_NAME")
+    @JvmName("firstOrNull")
+    @Deprecated("use get", ReplaceWith("get(key)"))
+    final fun <M : Message> getOrNull(key: Message.Key<M>): M? = get(key)
 }
 
 // region accessors
 
+/**
+ * 获取第一个类型为 [key] 的 [Message] 实例
+ *
+ * @param key 由各个类型消息的伴生对象持有. 如 [PlainText.Key]
+ */
+@JvmOverloads
+inline fun <M : Message> MessageChain.getOrFail(
+    key: Message.Key<M>,
+    crossinline lazyMessage: (key: Message.Key<M>) -> String = { key.typeName }
+): M = firstOrNull(key) ?: throw NoSuchElementException(lazyMessage(key))
+
+
 /**
  * 遍历每一个 [消息内容][MessageContent]
  */
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
index 1ae2b40df..65a06ee85 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
@@ -109,17 +109,17 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<MessageSo
      * 发送人.
      *
      * - 当 [OnlineMessageSource.Outgoing] 时为 [机器人][Bot.id]
-     * - 当 [OnlineMessageSource.Incoming] 时为发信 [目标好友][QQ.id] 或 [群][Group.id]
-     * - 当 [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] 或 [群][Group.id] (取决于 [OfflineMessageSource.kind])
+     * - 当 [OnlineMessageSource.Incoming] 时为发信 [目标好友][Friend.id] 或 [群][Group.id]
+     * - 当 [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][Friend.id] 或 [群][Group.id] (取决于 [OfflineMessageSource.kind])
      */
     abstract val fromId: Long
 
     /**
      * 消息发送目标.
      *
-     * - 当 [OnlineMessageSource.Outgoing] 时为发信 [目标好友][QQ.id] 或 [群][Group.id] 或 [临时消息][Member.id]
+     * - 当 [OnlineMessageSource.Outgoing] 时为发信 [目标好友][Friend.id] 或 [群][Group.id] 或 [临时消息][Member.id]
      * - 当 [OnlineMessageSource.Incoming] 时为 [机器人][Bot.id]
-     * - 当 [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] 或 [群][Group.id] 或 [临时消息][Member.id] (取决于 [OfflineMessageSource.kind])
+     * - 当 [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][Friend.id] 或 [群][Group.id] 或 [临时消息][Member.id] (取决于 [OfflineMessageSource.kind])
      */
     abstract val targetId: Long // groupCode / friendUin / memberUin
 
@@ -171,19 +171,19 @@ sealed class OnlineMessageSource : MessageSource() {
     }
 
     /**
-     * 消息发送人. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群员][Member].
-     * 即类型必定为 [Bot], [QQ] 或 [Member]
+     * 消息发送人. 可能为 [机器人][Bot] 或 [好友][Friend] 或 [群员][Member].
+     * 即类型必定为 [Bot], [Friend] 或 [Member]
      */
     abstract val sender: ContactOrBot
 
     /**
-     * 消息发送目标. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群][Group].
-     * 即类型必定为 [Bot], [QQ] 或 [Group]
+     * 消息发送目标. 可能为 [机器人][Bot] 或 [好友][Friend] 或 [群][Group].
+     * 即类型必定为 [Bot], [Friend] 或 [Group]
      */
     abstract val target: ContactOrBot
 
     /**
-     * 消息主体. 群消息时为 [Group]. 好友消息时为 [QQ], 临时消息为 [Member]
+     * 消息主体. 群消息时为 [Group]. 好友消息时为 [Friend], 临时消息为 [Member]
      * 不论是机器人接收的消息还是发送的消息, 此属性都指向机器人能进行回复的目标.
      */
     abstract val subject: Contact
@@ -436,7 +436,7 @@ inline val MessageChain.bot: Bot
  */
 @get:JvmSynthetic
 inline val MessageChain.source: MessageSource
-    get() = this[MessageSource]
+    get() = this.getOrFail(MessageSource)
 
 /**
  * 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.