{"record":{"id":"a4d8b07605730925","repo":"instructure/canvas-lms","slug":"no-such-context-for-context-type-context-id","errorCode":null,"errorMessage":"No such context for %{context_type}#%{context_id}","messagePattern":"No such context for %(.+?)#%(.+?)","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/set_friendly_description.rb","lineNumber":93,"sourceCode":"\n    unless context.available_outcome(outcome.id, allow_global: true)\n      raise GraphQL::ExecutionError, I18n.t(\n        \"Outcome %{outcome_id} is not available in context %{context_type}#%{context_id}\",\n        outcome_id: outcome.id.to_s,\n        context_id: context.id.to_s,\n        context_type: context.class.name\n      )\n    end\n  end\n\n  def get_context(context_type, context_id)\n    unless VALID_CONTEXTS.include?(context_type)\n      raise GraphQL::ExecutionError, I18n.t(\"Invalid context type\")\n    end\n\n    context_type.constantize.find_by(id: context_id).tap do |context|\n      unless context\n        raise GraphQL::ExecutionError, I18n.t(\n          \"No such context for %{context_type}#%{context_id}\",\n          context_type:,\n          context_id: context_id.to_s\n        )\n      end\n    end\n  end\n\n  def get_outcome(outcome_id)\n    LearningOutcome.active.find_by(id: outcome_id).tap do |outcome|\n      unless outcome\n        raise GraphQL::ExecutionError, I18n.t(\n          \"No such outcome for id %{id}\", { id: outcome_id }\n        )\n      end\n    end\n  end\nend","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/set_friendly_description.rb#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: unparsed asset string id\nconst [type, rawId] = contextAssetString.split('_');\nsetFriendlyDescription(input: { contextType: type.capitalize, contextId: rawId, ... })\n\n// after: verify the record exists first\nconst ctx = await canvas.get(`/api/v1/courses/${rawId}`);\nif (!ctx?.id) throw new Error(`context not found: ${type}_${rawId}`);\nsetFriendlyDescription(input: { contextType: 'Course', contextId: ctx.id, ... });","handlingStrategy":"validation","validationCode":"async function requireContext(contextType, contextId) {\n  const id = parseInt(contextId, 10);\n  if (!Number.isInteger(id) || id <= 0) throw new Error(`Invalid context id: ${contextId}`);\n  const base = contextType === 'Account' ? '/api/v1/accounts' : '/api/v1/courses';\n  const res = await fetch(`${base}/${id}`);\n  if (!res.ok) throw new Error(`No such context for ${contextType}#${id}`);\n  return res.json();\n}","typeGuard":"const isRealContextId = (v) =>\n  (typeof v === 'number' && Number.isInteger(v) && v > 0) ||\n  (typeof v === 'string' && /^\\d+$/.test(v));","tryCatchPattern":"try {\n  await setFriendlyDescription({ variables: { contextType, contextId, outcomeId, description } });\n} catch (e) {\n  if (e.message.startsWith('No such context for')) {\n    // parse contextType/contextId from the message for user feedback\n    invalidateContextCache();\n  } else { throw e; }\n}","preventionTips":["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"],"tags":["graphql","canvas-lms","record-not-found","context"],"backgroundTag":"record-not-found","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}