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

not found

Error message

not found

What it means

updateInstitutionalTagArchivedState loads the tag with InstitutionalTag.where(root_account_id: root_account.id).find_by(id:) — this variant does not filter on workflow_state, but still requires the record to exist under the current root account. If find_by returns nil it raises "not found". The resolver's trailing rescue of ActiveRecord::RecordNotFound provides the same message for any RecordNotFound raised later (e.g. during undestroy).

Solutions

  1. Confirm the tag exists under this root account: InstitutionalTag.where(root_account_id: root_account.id).find_by(id:) in console.
  2. Verify the Relay id is encoded for the InstitutionalTag type, not another type.
  3. Check the request resolves to the same root account that owns the tag.
  4. Handle the GraphQL errors entry and refresh the tag list before retrying.

Example fix

// before
updateInstitutionalTagArchivedState(input: { id: otherAccountTagId, archived: true })
// after
const tag = tagsByAccount[rootAccountId]?.find(t => t.id === tagId)
if (!tag) throw new Error('tag not found for this account')
updateInstitutionalTagArchivedState(input: { id: tagRelayId, archived: true })
Defensive patterns

Strategy: validation

Validate before calling

// confirm the tag exists under this account before archiving
const tags = await fetchAllInstitutionalTags(rootAccountId) // includes archived
if (!tags.some(t => t.id === tagId)) throw new Error(`tag ${tagId} not found for this account`)

Type guard

const isInstitutionalTag = (t) => !!t && t.__typename === 'InstitutionalTag'

Try / catch

try {
  await updateInstitutionalTagArchivedState(input)
} catch (e) {
  if (e.graphQLErrors?.some(g => g.message === 'not found')) {
    await refreshTagList() // wrong account or bad relay id
  } else { throw e }
}

Prevention

When it happens

Trigger: Passing an id that doesn't exist at all, belongs to a different root account, or is not decodable as an InstitutionalTag Relay id; a RecordNotFound raised from tag.undestroy when an unarchived state conflicts.

Common situations: Archiving an already-archived tag with a stale id; cross-account ids copied between environments; Relay id prepared for a different object type so the resolved raw id does not match any InstitutionalTag row.

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/3d02bc46292090d4. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/update_institutional_tag_archived_state.rb:39

# NOTE: Depends on InstitutionalTag and InstitutionalTagAssociation models

module Mutations
  class UpdateInstitutionalTagArchivedState < BaseMutation
    argument :archived, Boolean, required: true
    argument :id,
             ID,
             required: true,
             prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("InstitutionalTag")

    field :institutional_tag, Types::InstitutionalTagType, null: true

    def resolve(input:)
      root_account = context[:domain_root_account]
      raise GraphQL::ExecutionError, "feature flag is disabled" unless root_account.feature_enabled?(:institutional_tags)
      raise GraphQL::ExecutionError, "not authorized" unless root_account.grants_right?(current_user, session, :manage_institutional_tags_edit)

      tag = InstitutionalTag.where(root_account_id: root_account.id).find_by(id: input[:id])
      raise GraphQL::ExecutionError, "not found" unless tag

      input[:archived] ? tag.destroy : tag.undestroy

      { institutional_tag: tag }
    rescue ActiveRecord::RecordInvalid
      errors_for(tag)
    rescue ActiveRecord::RecordNotFound
      raise GraphQL::ExecutionError, "not found"
    end
  end
end

View on GitHub (pinned to 1c9f0bb801)