diff --git a/src/commands/thread.ts b/src/commands/thread.ts
index 87763e7..e6038c6 100644
--- a/src/commands/thread.ts
+++ b/src/commands/thread.ts
@@ -1,3 +1,4 @@
+import assert from 'assert'
 import { ChannelType, ThreadChannel } from 'discord.js'
 import { SlashCommand, SlashCreator, CommandContext } from 'slash-create'
 import { commandLog } from '../communication/interaction'
@@ -6,7 +7,7 @@ import {
   updateFeedbackThreadId,
   validatePendingSubmission
 } from '../db/submission'
-import { fetchSubmissionForContext } from '../utils/commands'
+import { fetchAnySubmissionForContext } from '../utils/commands'
 import { getAssignedGuilds } from '../utils/discordUtils'
 import { runCatching } from '../utils/request'
 
@@ -21,7 +22,7 @@ export default class ThreadCommand extends SlashCommand {
   }
 
   async run (ctx: CommandContext): Promise<void> {
-    const submission = await fetchSubmissionForContext(ctx)
+    const submission = await fetchAnySubmissionForContext(ctx)
 
     if (!submission) {
       return
@@ -29,6 +30,9 @@ export default class ThreadCommand extends SlashCommand {
 
     let existingThread: ThreadChannel | undefined
 
+    // Running commands in a thread with a raw submission should be impossible
+    assert(submission.state !== 'RAW', 'submission was in raw state')
+
     if (submission.state === 'ERROR') {
       commandLog.warning({
         type: 'text',
@@ -39,6 +43,21 @@ export default class ThreadCommand extends SlashCommand {
       return
     }
 
+    if (submission.state === 'ACCEPTED' || submission.state === 'DENIED') {
+      const { feedbackThread } = submission
+      if (!feedbackThread) {
+        commandLog.warning({
+          type: 'text',
+          content:
+          'Cannot add you, no thread exists.',
+          ctx
+        })
+        return
+      }
+
+      existingThread = feedbackThread
+    }
+
     if (submission.state === 'PROCESSING' || submission.state === 'PAUSED') {
       // Allow thread creation in paused state, as reviewers may need to contact submitters about warnings
       existingThread = submission.feedbackThread
@@ -85,6 +104,10 @@ export default class ThreadCommand extends SlashCommand {
         }),
       'rethrow'
     )
+
+    // We checked for the states above, this just lets TS infer it so we don't have any casting.
+    assert(submission.state === 'PROCESSING' || submission.state === 'PAUSED' || submission.state === 'WARNING', 'impossible')
+
     await updateFeedbackThreadId(submission, feedbackThread.id)
 
     await runCatching(
diff --git a/src/db/submission.ts b/src/db/submission.ts
index 1b6b28e..a24154a 100644
--- a/src/db/submission.ts
+++ b/src/db/submission.ts
@@ -212,6 +212,16 @@ export async function fetchSubmissionByMessageId (
     // from button votes, whereby the author must exist
     const author = await fetchAuthor(data.authorId)
 
+    // May or may not exist, do not abort if it does not
+    let feedbackThread
+    if (data.feedbackThreadId) {
+      try {
+        feedbackThread = await fetchFeedbackThread(data.feedbackThreadId)
+      } catch {
+        logger.warn(`Feedback thread for submission (message ID ${id}) did not exist`)
+      }
+    }
+
     const completed: CompletedSubmission = {
       ...data,
       state: data.state,
@@ -221,7 +231,8 @@ export async function fetchSubmissionByMessageId (
         source: data.sourceLinks,
         other: data.otherLinks
       },
-      author
+      author,
+      feedbackThread
     }
 
     return completed
@@ -385,11 +396,12 @@ async function resolvePrismaData (
 
   logger.trace('API requests successful')
 
-  const submission: AnySubmission = {
+  const submission = {
     ...data,
     state: data.state,
 
     feedbackThread,
+    author: undefined,
     tech: data.techUsed,
     links: {
       other: data.otherLinks,
diff --git a/src/types/submission.ts b/src/types/submission.ts
index 3598db5..82e5b04 100644
--- a/src/types/submission.ts
+++ b/src/types/submission.ts
@@ -76,8 +76,9 @@ export interface CompletedSubmission extends BaseSubmission {
   id: Cuid
   submittedAt: Date
 
-  // Author may no longer exist when we fetch in this state
-  author?: GuildMember
+  // Author / thread may no longer exist when we fetch in this state
+  author: GuildMember | undefined
+  feedbackThread: ThreadChannel | undefined
 }
 
 // These type guards exist for more readable code, and better TS behavior
diff --git a/src/utils/commands.ts b/src/utils/commands.ts
index 5f5dc4d..05a5cd4 100644
--- a/src/utils/commands.ts
+++ b/src/utils/commands.ts
@@ -1,8 +1,43 @@
 import { CommandContext } from 'slash-create'
 import { commandLog } from '../communication/interaction'
 import { internalLog } from '../communication/internal'
-import { fetchSubmissionByThreadId } from '../db/submission'
-import { PendingSubmission, ValidatedSubmission } from '../types/submission'
+import { fetchAnySubmissionByThreadId, fetchSubmissionByThreadId } from '../db/submission'
+import { AnySubmission, PendingSubmission, ValidatedSubmission } from '../types/submission'
+
+/**
+ * Fetches the submission for the given command context.
+ * This does NOT validate the state of the submission in any way
+ * This relies on the thread ID to perform the lookup.
+ */
+export async function fetchAnySubmissionForContext (ctx: CommandContext): Promise<AnySubmission | undefined> {
+  const id = ctx.channelID
+
+  if (!id) {
+    return void commandLog.error({
+      type: 'text',
+      content: 'Interaction came with no thread ID.',
+      ctx
+    })
+  }
+
+  const submission = await fetchAnySubmissionByThreadId(id)
+
+  if (!submission) {
+    commandLog.error({
+      type: 'text',
+      content: `Could not look up submission for channel ID ${id}`,
+      ctx
+    })
+
+    return void internalLog.error({
+      type: 'text',
+      content: `Could not look up submission for channel ID ${id}`,
+      ctx: undefined
+    })
+  }
+
+  return submission
+}
 
 /**
  * Fetches the submission for the given command context.