instructure/canvas-lms · error · Lti::IMS::AdvantageErrors::InvalidResourceLinkIdFilter

Tool does not have access to rlid or rlid does not exist

Error message

Tool does not have access to rlid or rlid does not exist

What it means

Guard in MembershipsProvider#resource_link: for an NRPS request with an rlid, either the tool lacks access to that Lti::ResourceLink or the rlid doesn't resolve — the resource link's current external tool doesn't match the requesting tool (by id or by same registration/dev key in the root account). Raised as InvalidResourceLinkIdFilter.

Solutions

  1. Ensure the LTI launch/NRPS call uses the same tool (or registration dev key) that owns the resource link
  2. Verify the rlid value matches an existing Lti::ResourceLink uuid
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at app/controllers/lti/ims/providers/memberships_provider.rb:117 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at app/controllers/lti/ims/providers/memberships_provider.rb:117

      return nil unless rlid?
      return @resource_link if defined?(@resource_link)

      rl = Lti::ResourceLink.find_by(resource_link_uuid: rlid)
      if rl.present?
        # context here is a decorated context, we want the original
        current_tool = rl.current_external_tool(Lti::IMS::Providers::MembershipsProvider.unwrap(context))
        # Allow access if IDs match exactly, or if both are from the same LTI 1.3
        # registration (same developer key) within the same root account. The latter
        # handles cases where the same registration is installed at multiple context
        # levels (e.g., course and account), and a resource link created by one
        # installation is accessed by another. The root_account_id guard prevents
        # a global/inherited developer key from granting cross-root-account access.
        unless current_tool &&
               (current_tool.id == tool.id ||
                (tool.use_1_3? && tool.developer_key_id.present? &&
                 current_tool.developer_key_id == tool.developer_key_id &&
                 current_tool.root_account_id == tool.root_account_id))
          raise Lti::IMS::AdvantageErrors::InvalidResourceLinkIdFilter.new(
            "Tool does not have access to rlid #{rlid}",
            api_message: "Tool does not have access to rlid or rlid does not exist"
          )
        end
      end

      @resource_link = rl
    end

    def content_tag
      return nil unless resource_link

      ContentTag.find_by(associated_asset: resource_link)
    end

    def role
      controller.params[:role]
    end

View on GitHub (pinned to 1c9f0bb801)