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

Cannot request more than 100 courses at once

Error message

Cannot request more than 100 courses at once

What it means

The `courses` resolver caps a single request at 100 course IDs (graphql/legacy or SIS). After the either/or argument check, it raises this GraphQL::ExecutionError when `ids` or `sis_ids` contains more than 100 entries.

Solutions

  1. Chunk the ID list into batches of at most 100 and issue multiple `courses` queries.
  2. Prefer the coursesConnection for enumeration instead of long ID lists.
  3. Filter the ID list server-side or by enrollment before querying so only needed courses are requested.

Example fix

// before
query { courses(ids: $allIds) { _id name } } // allIds.length = 500
// after
const batches = chunk(allIds, 100);
const results = await Promise.all(batches.map(ids => gql(`query($ids:[ID!]){ courses(ids:$ids){ _id name } }`, { ids })));
Defensive patterns

Strategy: validation

Validate before calling

const list = vars.ids || vars.sisIds || [];
if (list.length > 100) throw new Error(`courses accepts at most 100 ids, got ${list.length}`);

Type guard

const withinCourseLimit = (vars) => ((vars.ids || vars.sisIds) || []).length <= 100;

Try / catch

try { return await gql(COURSES_QUERY, vars); } catch (e) { if (e.message.includes('more than 100 courses')) { return (await Promise.all(chunk(list, 100).map(b => gql(COURSES_QUERY, mkVars(b))))).flat(); } throw e; }

Prevention

When it happens

Trigger: query { courses(ids: [/* 101+ ids */]) } or courses(sisIds: [/* 101+ */]) — any request whose list length exceeds 100 after passing the ids/sisIds exclusivity check.

Common situations: Bulk dashboards exporting all enrollments in one query; admin tooling iterating over an account's courses without pagination; a sync job accumulating IDs and sending them in one shot.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/types/query_type.rb:260

                                    Enrollment.state_by_date_rank_sql,
                                    Arel.sql("enrollments.id")
                                  )

      InstructorQuery.new(deduplicated_ids_subquery)
    end

    field :courses,
          [Types::CourseType],
          "Courses by IDs that are viewable by the current user",
          null: true do
      argument :ids, [ID], "graphql or legacy course IDs", required: false, prepare: GraphQLHelpers.relay_or_legacy_ids_prepare_func("Course")
      argument :sis_ids, [String], "ids from the original SIS system", required: false
    end
    def courses(ids: nil, sis_ids: nil)
      raise GraphQL::ExecutionError, "Must specify exactly one of ids or sisIds" if (ids && sis_ids) || !(ids || sis_ids)

      course_ids = ids || sis_ids
      raise GraphQL::ExecutionError, "Cannot request more than 100 courses at once" if course_ids&.length.to_i > 100

      courses = if ids
                  current_user&.accessible_courses_by_ids(ids, preload_courses: true)
                elsif sis_ids
                  current_user&.accessible_courses_by_sis_ids(sis_ids, preload_courses: true)
                end

      courses&.index_by(&:id)
             &.values
             &.sort_by! do |course|
               Canvas::ICU.collation_key(course.nickname_for(current_user))
             end
    end

    field :module_item, Types::ModuleItemType, null: true do
      description "ModuleItem"
      argument :id,
               ID,

View on GitHub (pinned to 1c9f0bb801)