I was in a similar situation at one point, with the added twist that the frontend was software and the backend was hardware (no access to each other's codebases). You mentioned:
the QE team will file a bug stating that "doing X, then
Y, then Z on the UI will throw an error when it shouldn't".
and then these tickets would get forwarded to you. When I got tickets like those, I would kick them back as "needs more information". I don't have anything UI related on my backend, so the ticket from the QE team doesn't tell me much that's meaningful to me. Instead, we'd essentially require the frontend team to write up a separate child ticket - not reassign the original ticket - that says "when I send a such-and-such request to the backend that's formatted like this, the result is truncated".
This prevents the frontend team from lazily chucking issues over the wall and having you do the work. They have to debug the issue up to the interface between us. The end result was that 95% of the bugs they sent to us were actually backend issues. The process of debugging up to the interface would make it pretty clear which side the problem was on. It's hard to write up a description of what the backend is doing wrong when the problem's on the frontend. If they try anyway, such tickets are usually trivial to identify by (for example) showing that the same process works as expected when using a different frontend.
Using a second ticket between the frontend and backend teams also means you can close invalid tickets with extreme prejudice and it doesn't impact the QE team's original ticket at all. During a retrospective, you can show the number of tickets filed by the frontend team that were either invalid or didn't have enough information to be actionable, which should make the problem a lot more visible and obvious to management.
Essentially, stop crossing over the interface between the frontend and backend. You actually have the access and skill set to peek into each other's codebases (unlike my case), but just because you can doesn't mean you should. A big part of the reason for separating software into pieces like that is so that they can treat each other like black boxes with clearly defined interfaces. A backend bug should be ticketable without any reference whatsoever to a particular frontend, only to the backend's interface. If you have to lean across that boundary into another team's code to investigate your ticket, then whoever filed that ticket hasn't finished with their part yet.
I found it particularly helpful to have an alternate, simplified frontend to use for testing. My team rarely did testing using the official frontend (GUI). We put together a command-line utility from scratch that could exercise all the backend functions individually, and that contained none of the business logic that was in the frontend. That let us easily test our backend in isolation and verify its behavior against the spec. When a bug came in from the frontend team, we'd test the same sequence of functions manually using our utility. If we saw the same problem, the bug was most likely in the backend. When it worked fine for us, the problem was almost always in the frontend. We could easily identify tickets that weren't actually backend issues with a 5 minute test instead of spending 2 hours digging into it.