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
- Query the OutcomeCalculationMethod via GraphQL first to confirm the id exists and is active
- Use the correct relay global id or valid legacy numeric id
- Recreate or restore the outcome calculation method if it was deleted
- 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
- Fetch and validate the global id immediately before deletion
- Refresh outcome lists after any mutation
- Account for soft-deleted records being invisible to active scope
- Use the relay global id, not names or legacy fragments
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
- Unable to find OutcomeProficiency
- Allocation rule not found
- Assignment not found
- assignment not found: #
- assignment not found
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)