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

Outcome is not available in context #

Error message

Outcome %{outcome_id} is not available in context %{context_type}#%{context_id}

What it means

Raised in SetFriendlyDescriptionMutation#validate! after permission checks pass, when context.available_outcome(outcome.id, allow_global: true) returns nil. This means the outcome being given a friendly description is not part of the context's available outcome set (course/account outcome tree, even counting global outcomes), so the mutation refuses to attach a friendly description in that context.

Solutions

  1. Verify the outcome is actually available in the target context (Course#available_outcome / account outcome tree) and use an outcome that is linked there
  2. Check the outcome_id/context pairing: ensure you are passing the context where the outcome was imported or linked
  3. If the outcome should be available, add it to the context (import/link the outcome into the course or account) and retry
  4. Restore or re-add the outcome if it was deleted or unlinked from the context's outcome tree

Example fix

// before: blindly calling with any outcome id
setFriendlyDescription(input: { contextId, contextType: 'Course', outcomeId, description })

// after: pre-check availability in context
const outcome = course.outcomes.find(o => o.id === outcomeId);
if (!outcome) throw new Error(`outcome ${outcomeId} not available in course ${contextId}`);
setFriendlyDescription(input: { contextId, contextType: 'Course', outcomeId, description });
Defensive patterns

Strategy: validation

Validate before calling

async function assertOutcomeInContext(contextType, contextId, outcomeId) {
  const endpoint = contextType === 'Account'
    ? `/api/v1/accounts/${contextId}/outcomes?outcome_ids[]=${outcomeId}`
    : `/api/v1/courses/${contextId}/outcome_group_links`;
  const res = await fetch(endpoint);
  const data = await res.json();
  const linked = Array.isArray(data)
    ? data.some(l => l?.outcome?.id === outcomeId)
    : (data?.outcome_groups || []).some(g => (g.outcomes || []).some(o => o.id === outcomeId));
  if (!linked) throw new Error(`Outcome ${outcomeId} not available in ${contextType} ${contextId}`);
}

Type guard

const hasLinkedOutcome = (outcomeLinks, outcomeId) =>
  Array.isArray(outcomeLinks) &&
  outcomeLinks.some(l => Number(l?.outcome?.id) === Number(outcomeId));

Try / catch

try {
  await setFriendlyDescription({ variables: { contextType, contextId, outcomeId, description } });
} catch (e) {
  if (e.message.includes('is not available in context')) {
    showBanner('This outcome is not linked to this course/account.');
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling the setFriendlyDescription mutation with an outcomeId that is not linked/available in the given context (context_type + context_id): an outcome from another course/account, a deleted or unlinked outcome, or an outcome id supplied for the wrong context entirely.

Common situations: Frontend passing an outcome id from a different course after a copy/import; outcomes removed from an account's outcome tree while a stale UI still references them; global outcomes used with a context whose account chain does not include them; scripts iterating outcome ids from one environment against another.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

      friendly_description.save!

    else
      friendly_description.destroy if friendly_description.persisted?
      friendly_description.description = ""
    end

    {
      outcome_friendly_description: friendly_description
    }
  end

  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:,

View on GitHub (pinned to 1c9f0bb801)