The has_submitted_submissions API trap

The Canvas Assignments API has a boolean called has_submitted_submissions, and it does not mean what it looks like it means: it flips true when any student in the course submits, and says nothing about you. Instructure's own docs state it — "submitted to by at least one student." Any app that reads it as "the current user submitted" will mark your assignment done because a classmate turned theirs in. We know because we shipped exactly that bug in Margin's early Canvas sync, and removed it; the correct per-user signal is the submission include.

What you see

If you are a student, you see it second-hand: a planner or dashboard built on this field can close an assignment you have not started, because the trigger is a classmate's submission rather than yours. Being told you are finished by something that never looked at your work is exactly the wrong kind of reassurance.

If you are the developer of that app, you see a field named in the plainest possible way — has_submitted_submissions — sitting right on the assignment object you already fetched, requiring no extra include and no extra request. It reads as a free answer to "is this done?" It is not.

Why it happens

The value is computed across the whole assignment, not for the person asking. In Canvas's own source, abstract_assignment.rb defines it as:

def has_submitted_submissions?
  return @has_submitted_submissions unless @has_submitted_submissions.nil?
  submitted_count > 0
end

submitted_count counts submissions on the assignment, across everyone enrolled, and the boolean is whether that count is above zero. One submission anywhere in the course flips the boolean for everyone who reads it. Instructure's Assignments API reference says so directly in the field description: "If true, the assignment has been submitted to by at least one student"

Whatever it was added for, it is not scoped to the person asking. Read from a student-scoped token it is still true, still course-wide, and still silent about the person holding the token.

What you can do about it

If you are building on the Canvas API: ask for the per-user object instead. On the Assignments endpoint, include[]=submission returns "The current user's current +Submission+" (the plus signs are the doc's own markup) — documented on the same page as the trap. Read that object's workflow_state and submitted_at, and treat a missing submission object as unknown, not as done.

Two habits worth adopting alongside it:

If you are a student whose planner did this: check the assignment page in Canvas itself, or the gradebook, before believing any third-party app that says you are done. The submission record on Canvas is the source of truth; a synced tool is a convenience layer over it. Margin shows what Canvas exposes — check your syllabus too.

Evidence