instructure/canvas-lms · error · GraphQL::ExecutionError

not found

Error message

not found

What it means

create_conversation#resolve rescues ActiveRecord::RecordNotFound and raises GraphQL::ExecutionError 'not found'. Any record needed to build the conversation (recipient User, course/group context, participant) missing from the DB makes the whole mutation fail with this opaque message.

Solutions

  1. Validate every recipient id resolves to an active User before calling
  2. Confirm the context_code (course_/group_) references an existing, active context
  3. Remove stale recipients and retry; find the failing id by querying each in console
  4. Check shard routing so cross-shard user ids load in the current context

Example fix

// before
createConversation(input: { recipients: ["4", "999"] }) // user 999 deleted
// after
valid_ids = User.active.where(id: [4, 999]).pluck(:id)
createConversation(input: { recipients: valid_ids.map(&:to_s), body: "hi" })
Defensive patterns

Strategy: validation

Validate before calling

const users = await Promise.all(recipientIds.map(id => canvas.get(`/api/v1/users/${id}`).catch(() => null)))
if (users.some(u => !u)) throw new Error('one or more recipients not found')

Type guard

function allRecipientsValid(users) { return Array.isArray(users) && users.length > 0 && users.every(u => u != null && u.id != null && u.workflow_state !== 'deleted') }

Try / catch

try {
  await client.mutate({ mutation: CREATE_CONVERSATION, variables: { recipients, body } })
} catch (e) {
  if (e.message === 'not found') {
    // bisect recipients to find the stale id, then resend without it
  }
  throw e
}

Prevention

When it happens

Trigger: Calling createConversation with recipient ids, context codes, or attachment/media ids that don't resolve: invalid recipient user ids, deleted context course, missing conversation participants, or bad enrollement-linked records.

Common situations: Recipient user deleted or on another shard; context_code references a deleted course/group; bulk recipients list contains one stale id so the entire send fails; API clients caching old user ids.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/33ea6fbd402882e9. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/create_conversation.rb:148

        InstStatsd::Statsd.distributed_increment("inbox.conversation.sent.react")
        InstStatsd::Statsd.count("inbox.message.sent.recipients.react", recipients.count)
        if message.has_media_objects || input[:media_comment_id]
          InstStatsd::Statsd.distributed_increment("inbox.message.sent.media.react")
        end
        if message[:attachment_ids].present?
          InstStatsd::Statsd.distributed_increment("inbox.message.sent.attachment.react")
        end
        if context_type == "Account" || context_type.nil?
          InstStatsd::Statsd.distributed_increment("inbox.conversation.sent.account_context.react")
        end
        if input[:bulk_message]
          InstStatsd::Statsd.distributed_increment("inbox.conversation.sent.individual_message_option.react")
        end
        return { conversations: [conversation] }
      end
    end
  rescue ActiveRecord::RecordNotFound
    raise GraphQL::ExecutionError, "not found"
  rescue ActiveRecord::RecordInvalid => e
    errors_for(e.record)
  rescue ConversationsHelper::InvalidContextError
    validation_error(
      I18n.t(
        "No context found for the following context code: %{context_code}",
        { context_code: input[:context_code] }
      ),
      attribute: "context_code"
    )
  rescue ConversationsHelper::InvalidContextPermissionsError
    validation_error(
      I18n.t(
        "Unable to send messages to users in %{context_name}",
        { context_name: context.name }
      ),
      attribute: "permissions"
    )

View on GitHub (pinned to 1c9f0bb801)