instructure/canvas-lms · error · SubmissionError
No attachments found for the following ids
Error message
No attachments found for the following ids: %{ids} What it means
CreateSubmissionDraft#validate_file_ids! checks each submitted file id against the set of attachment ids the current user is allowed to submit (their own files, group files, etc.). If any file id is not in the valid set, it raises SubmissionError listing the invalid ids. This prevents users from attaching files they do not own or that do not exist.
Solutions
- Re-query the current user's available files and submit only ids returned there.
- Remove the offending ids named in the error message before retrying.
- Re-upload the deleted file and use the new attachment id.
- Ensure you pass legacy numeric ids (or the expected format) consistently, not relay/global ids the validator can't match.
Example fix
// before fileIds: [123, 456] // 456 deleted // after fileIds: [123, 789] // re-upload and use fresh Attachment id
Defensive patterns
Strategy: validation
Validate before calling
function assertValidFileIds(submittedIds, allowedIds) {
const bad = submittedIds.filter(id => !allowedIds.includes(String(id)));
if (bad.length) throw new SkipError(`invalid file ids: ${bad.join(',')}`);
} Type guard
function allOwned(attachments, userId) { return attachments.every(a => a?.uploaderId === userId || a?.ownerId === userId); } Try / catch
try {
await createSubmissionDraft({ fileIds })
} catch (e) {
if (e.message.includes('No attachments found')) {
fileIds = fileIds.filter(id => !e.message.includes(id)); // drop bad ids and retry
} else throw e;
} Prevention
- Submit only ids returned by the files query for the current user.
- Normalize ids to the same string format the validator uses.
- Purge stale ids from draft state after uploads/deletions.
- For group submissions, use group-scoped file listings.
When it happens
Trigger: Passing fileIds to createSubmissionDraft where at least one id is not in valid_attachment_ids: file deleted, file owned by another user, wrong ids, or an id string with wrong format (numeric vs relay id mismatch).
Common situations: Client uploaded files then re-uploaded/deduplicated and kept stale ids; submitting on behalf of a group with another member's file ids that aren't in the allowed set; ids from a different user's session; hard-coded test ids.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- A maximum of 50 assessees can be provided at once
- A maximum of 50 assessors can be provided at once
- All ConversationMessages must exist within the same…
- Anonymous assignments must be manually posted
- Assignment overrides are not allowed in the parent…
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/4e4e8075b242c870.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/create_submission_draft.rb:151
shard.activate do
valid_attachment_ids = get_attachment_ids(attachments.map(&:id))
validate_file_ids!(attachments, valid_attachment_ids)
return_attachments += Attachment.active.where(id: valid_attachment_ids)
end
end
return_attachments.each do |attachment|
verify_authorized_action!(attachment, :read)
end
return_attachments
end
def validate_file_ids!(file_id_attachments, valid_attachment_ids)
file_ids = file_id_attachments.pluck(:id).map(&:to_s)
file_ids.each do |file_id|
next if valid_attachment_ids.include?(file_id)
raise SubmissionError, I18n.t(
"No attachments found for the following ids: %{ids}",
{ ids: file_ids - valid_attachment_ids }
)
end
end
# TODO: move this into the model
def verify_allowed_extensions!(assignment, attachments)
return if assignment.allowed_extensions.blank?
raise SubmissionError, I18n.t("Invalid file type") unless attachments.all? do |attachment|
attachment_extension = attachment.after_extension || ""
assignment.allowed_extensions.include?(attachment_extension.downcase)
end
end
def get_attachment_ids(file_ids)
return [] if file_ids.empty?View on GitHub (pinned to 1c9f0bb801)