There are a lot of reasons the move might not work, but the message that shows up should be a clue why it didn't work.
"But it failed" means that the opposing Pokemon already suffers from a status condition.*
In the case of trying to poison a Steel or Poison type Pokemon, it will say "It doesn't affect <Pokemon name>." This is also what happens when you try to put a Pokemon with Vital Spirit (eg: Primeape) to sleep.
The attack can also miss, in which case it will say "Bellsprout's attack missed." Both those moves hit 75% of the time under normal conditions (and are further reduced when opposing Pokemon's evasion rises or Bellsprout's accuracy lowers).
There are also moves like Safeguard that protect Pokemon from being afflicted by these status conditions. In that case I think it straight up says "Foe <Pokemon name> was protected by safeguard." I don't remember though, this could be another reason why you might get the "But it failed" message.
Hope that helps!
*That is, the five "non-volatile status conditions" that show up under the opposing Pokemon's name / next to their health bar: Burnt, Paralyzed, Frozen, Asleep, and Poisoned. If they're merely confused, infatuated, seeded, etc the "But it failed" message won't be a problem.