instructure/canvas-lms · error
Invalid Attachment
Error message
Invalid Attachment
What it means
During assignment submission (student_annotation type), Canvas raises 'Invalid Attachment' when annotatable_attachment_id is blank, or when the attachment id submitted does not match the assignment's configured annotatable_attachment_id. This guards against stale tabs submitting annotation work against a different file.
Solutions
- Refresh the assignment page and resubmit so the current annotatable_attachment_id is used
- Verify the API call includes a non-blank annotatable_attachment_id matching the assignment's annotatable_attachment_id
- Re-publish/re-select the annotated document consistently, then have students reload before submitting
Example fix
# before
submit({ submission_type: 'student_annotation' })
# after
submit({ submission_type: 'student_annotation', annotatable_attachment_id: assignment.annotatable_attachment_id }) Defensive patterns
Strategy: validation
Validate before calling
const attachmentId = opts.annotatable_attachment_id;
if (attachmentId == null || Number(attachmentId) === 0) {
throw new Error('annotatable_attachment_id is required for student_annotation submissions');
}
if (Number(attachmentId) !== Number(assignment.annotatable_attachment_id)) {
throw new Error('Stale tab: reload the page and resubmit');
} Type guard
function hasValidAnnotatableAttachment(opts, assignment) {
const id = Number(opts?.annotatable_attachment_id);
return Number.isInteger(id) && id > 0 && id === Number(assignment?.annotatable_attachment_id);
} Try / catch
try {
await submitAnnotation(submission);
} catch (e) {
if (e.message === 'Invalid Attachment') {
promptReload('The annotated document changed. Please refresh and try again.');
}
} Prevention
- Always read annotatable_attachment_id from freshly loaded assignment data
- Invalidate/push refresh to open submission pages when the annotated document changes
- Validate the attachment id client-side against the assignment before submit
- Cover stale-tab resubmission in integration tests
When it happens
Trigger: Submitting an ePortfolio/annotation attempt with no annotatable_attachment_id; a student with a stale browser tab submits after the teacher changed the assignment's annotated file so the ids differ.
Common situations: Teacher swaps the annotated document after students began work; student opens submit page, leaves it open, assignment config changes, then submits; direct API calls omitting the attachment id.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Invalid submission type
- Attachment verifier token expired: #
- Attachment verifier token id mismatch. token id: #
- Attachment verifier token invalid: #
- failed to reclaim attachment #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/d6e5c2357dcbca88.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/abstract_assignment.rb:2752
].freeze
ALLOWABLE_SUBMIT_HOMEWORK_OPTS = (SUBMIT_HOMEWORK_ATTRS +
%w[comment group_comment attachments require_submission_type_is_valid resource_link_lookup_uuid student_id]).to_set
def submit_homework(original_student, opts = {})
raise "Student Required" unless original_student
eula_timestamp = opts[:eula_agreement_timestamp]
webhook_info = assignment_configuration_tool_lookups.take&.webhook_info
should_add_proxy = false
if opts[:proxied_student]
current_user = original_student
original_student = opts[:proxied_student]
should_add_proxy = true
end
if opts[:submission_type] == "student_annotation"
raise "Invalid Attachment" if opts[:annotatable_attachment_id].blank?
raise "Invalid submission type" unless annotated_document?
# Prevent the case where a user clicks Submit on a stale tab, expecting
# to submit one set of work, only for another set to be submitted
# instead.
raise "Invalid Attachment" if opts[:annotatable_attachment_id].to_i != annotatable_attachment_id
end
# Only allow a few fields to be submitted. Cannot submit the grade of a
# homework assignment, for instance.
opts.each_key do |k|
opts.delete(k) unless ALLOWABLE_SUBMIT_HOMEWORK_OPTS.include?(k.to_s)
end
comment = opts.delete(:comment)
group_comment = opts.delete(:group_comment)
group, students = group_students(original_student)
homeworks = []
primary_homework = nilView on GitHub (pinned to 1c9f0bb801)