instructure/canvas-lms · error · GraphQL::ExecutionError
No such context for #
Error message
No such context for %{context_type}#%{context_id} What it means
Raised in SetFriendlyDescriptionMutation#get_context when context_type passes the VALID_CONTEXTS whitelist but context_type.constantize.find_by(id: context_id) returns nil. The context class is valid but no record with that id exists, so the mutation aborts with a message embedding the type and id.
Solutions
- Verify the context_id exists (GET /api/v1/courses/:id or /api/v1/accounts/:id) and fix the id passed to the mutation
- Ensure contextId is serialized as the numeric id, not 'undefined'/'null'/asset-string forms like 'course_42'
- Check the request targets the correct shard/root account containing that course or account
- If the record was deleted, restore it or use a different context for the friendly description
Example fix
// before: unparsed asset string id
const [type, rawId] = contextAssetString.split('_');
setFriendlyDescription(input: { contextType: type.capitalize, contextId: rawId, ... })
// after: verify the record exists first
const ctx = await canvas.get(`/api/v1/courses/${rawId}`);
if (!ctx?.id) throw new Error(`context not found: ${type}_${rawId}`);
setFriendlyDescription(input: { contextType: 'Course', contextId: ctx.id, ... }); Defensive patterns
Strategy: validation
Validate before calling
async function requireContext(contextType, contextId) {
const id = parseInt(contextId, 10);
if (!Number.isInteger(id) || id <= 0) throw new Error(`Invalid context id: ${contextId}`);
const base = contextType === 'Account' ? '/api/v1/accounts' : '/api/v1/courses';
const res = await fetch(`${base}/${id}`);
if (!res.ok) throw new Error(`No such context for ${contextType}#${id}`);
return res.json();
} Type guard
const isRealContextId = (v) => (typeof v === 'number' && Number.isInteger(v) && v > 0) || (typeof v === 'string' && /^\d+$/.test(v));
Try / catch
try {
await setFriendlyDescription({ variables: { contextType, contextId, outcomeId, description } });
} catch (e) {
if (e.message.startsWith('No such context for')) {
// parse contextType/contextId from the message for user feedback
invalidateContextCache();
} else { throw e; }
} Prevention
- Parse numeric ids out of asset strings instead of passing 'undefined' or 'course_42' fragments
- Re-verify course/account existence after deletions or when switching between test and production
- Keep context ids on the correct shard/root account in multi-shard Canvas installs
- Cache course/account ids with a short TTL and revalidate on mutation failures
When it happens
Trigger: Calling setFriendlyDescription with a valid contextType ('Course' or 'Account') but a context_id that does not exist, was deleted, is on another shard, or is non-numeric/garbage that find_by cannot match.
Common situations: Stale course/account ids after deletion or environment switch (test vs prod); unparsed input where contextId is nil or a string like 'undefined'; cross-shard id mistakes in Canvas's Switchman setup; truncated or mistyped ids in API scripts.
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
- A course with that id does not exist
- Outcome is not available in context #
- and cannot be used together
- ActiveRecord::RecordNotFound
- Allocation rule not found
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/a4d8b07605730925.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/set_friendly_description.rb:93
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 }
)
end
end
end
endView on GitHub (pinned to 1c9f0bb801)