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

Invalid context type

Error message

Invalid context type

What it means

Raised in SetFriendlyDescriptionMutation#get_context when the supplied context_type string is not in VALID_CONTEXTS (the whitelist of context classes the mutation supports, e.g. Course/Account). The mutation rejects the request before even attempting to load a record, because constantize on arbitrary strings would be unsafe.

Solutions

  1. Pass exactly one of the whitelisted context types (check VALID_CONTEXTS in app/graphql/mutations/set_friendly_description.rb — 'Course' or 'Account') with correct capitalization
  2. Normalize the caller's context type string (e.g. 'course'.capitalize) before sending the mutation
  3. If the object is a Section/Group/User, find the owning Course or Account and use that as the context instead
  4. If a new context type is legitimately needed, add it to VALID_CONTEXTS and redeploy (server-side change)

Example fix

// before: raw polymorphic string
const [type, id] = assetString.split('_');
setFriendlyDescription(input: { contextType: type, contextId: id, ... }) // 'course' -> Invalid context type

// after: normalize and whitelist
const CONTEXT_TYPES = ['Course', 'Account'];
const type = assetString.split('_')[0].capitalize;
if (!CONTEXT_TYPES.includes(type)) throw new Error(`unsupported context type: ${type}`);
setFriendlyDescription(input: { contextType: type, contextId: id, ... });
Defensive patterns

Strategy: validation

Validate before calling

const VALID_CONTEXTS = ['Course', 'Account'];
function normalizeContextType(assetStringOrType) {
  const raw = assetStringOrType.includes('_')
    ? assetStringOrType.split('_')[0]
    : assetStringOrType;
  const type = raw.charAt(0).toUpperCase() + raw.slice(1).toLowerCase();
  if (!VALID_CONTEXTS.includes(type)) {
    throw new Error(`Unsupported context type: ${raw}. Use Course or Account.`);
  }
  return type;
}

Type guard

const isValidContextType = (t) =>
  typeof t === 'string' && ['Course', 'Account'].includes(t);

Try / catch

try {
  await setFriendlyDescription({ variables: { contextType, contextId, outcomeId, description } });
} catch (e) {
  if (e.message === 'Invalid context type') {
    console.error(`Bad contextType '${contextType}'; expected Course or Account`);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling setFriendlyDescription with contextType values that are not whitelisted, e.g. lowercase 'course', 'Section', 'User', 'Group', or any other class name outside VALID_CONTEXTS.

Common situations: Frontend deriving context type from a polymorphic asset string like 'course_123' and passing the raw lowercase segment; new integration code guessing context types; typos ('Couse', 'Courses'); using valid Canvas contexts (sections, groups) the mutation simply does not support.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/set_friendly_description.rb:88

  private

  def validate!(context, outcome)
    verify_authorized_action!(context, :manage_outcomes)

    unless context.available_outcome(outcome.id, allow_global: true)
      raise GraphQL::ExecutionError, I18n.t(
        "Outcome %{outcome_id} is not available in context %{context_type}#%{context_id}",
        outcome_id: outcome.id.to_s,
        context_id: context.id.to_s,
        context_type: context.class.name
      )
    end
  end

  def get_context(context_type, context_id)
    unless VALID_CONTEXTS.include?(context_type)
      raise GraphQL::ExecutionError, I18n.t("Invalid context type")
    end

    context_type.constantize.find_by(id: context_id).tap do |context|
      unless context
        raise GraphQL::ExecutionError, I18n.t(
          "No such context for %{context_type}#%{context_id}",
          context_type:,
          context_id: context_id.to_s
        )
      end
    end
  end

  def get_outcome(outcome_id)
    LearningOutcome.active.find_by(id: outcome_id).tap do |outcome|
      unless outcome
        raise GraphQL::ExecutionError, I18n.t(
          "No such outcome for id %{id}", { id: outcome_id }

View on GitHub (pinned to 1c9f0bb801)