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

Unable to find OutcomeCalculationMethod

Error message

Unable to find OutcomeCalculationMethod

What it means

The deleteOutcomeCalculationMethod mutation raises "Unable to find OutcomeCalculationMethod" when OutcomeCalculationMethod.active.find_by(id:) returns nil — i.e. no active record exists with the parsed relay/legacy id. The active scope excludes soft-deleted records, so a soft-deleted method also produces this error.

Solutions

  1. Query the OutcomeCalculationMethod via GraphQL first to confirm the id exists and is active
  2. Use the correct relay global id or valid legacy numeric id
  3. Recreate or restore the outcome calculation method if it was deleted
  4. Check workflow_state is active in the outcome_calculation_methods table

Example fix

// before
record = OutcomeCalculationMethod.active.find_by(id: record_id)
raise GraphQL::ExecutionError, "Unable to find OutcomeCalculationMethod" if record.nil?
// after
record = OutcomeCalculationMethod.find_by(id: record_id)
if record.nil? || record.workflow_state != "active"
  raise GraphQL::ExecutionError, "Unable to find OutcomeCalculationMethod"
end
Defensive patterns

Strategy: validation

Validate before calling

const method = await query(outcomeCalculationMethod, { id });
if (!method || method.workflowState !== "active") throw new NotFound(id);

Type guard

function isActiveMethod(m) {
  return m != null && m._id != null && m.workflowState === "active";
}

Try / catch

try {
  await client.mutate(DELETE_OUTCOME_CALCULATION_METHOD, { id });
} catch (e) {
  if (e.message === "Unable to find OutcomeCalculationMethod") {
    refreshList(); // stale id
  } else throw e;
}

Prevention

When it happens

Trigger: Calling deleteOutcomeCalculationMethod with an id of a nonexistent method, a soft-deleted (workflow_state != active) method, or a mistyped id that parses but matches nothing.

Common situations: Stale client caches after another user deleted the calculation method, double-submitted mutations, or test fixtures cleaned up between calls.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/delete_outcome_calculation_method.rb:37

#

class Mutations::DeleteOutcomeCalculationMethod < Mutations::BaseMutation
  graphql_name "DeleteOutcomeCalculationMethod"

  # input arguments
  argument :id, ID, required: true

  # the return data if the delete is successful
  field :outcome_calculation_method_id, ID, null: false

  def self.outcome_calculation_method_id_log_entry(_entry, context)
    context[:deleted_models][:outcome_calculation_method].context
  end

  def resolve(input:)
    record_id = GraphQLHelpers.parse_relay_or_legacy_id(input[:id], "OutcomeCalculationMethod")
    record = OutcomeCalculationMethod.active.find_by(id: record_id)
    raise GraphQL::ExecutionError, "Unable to find OutcomeCalculationMethod" if record.nil?
    raise GraphQL::ExecutionError, "insufficient permission" unless record.context.grants_right? current_user, :manage_proficiency_calculations

    context[:deleted_models][:outcome_calculation_method] = record
    record.destroy
    { outcome_calculation_method_id: record.id }
  end
end

View on GitHub (pinned to 1c9f0bb801)