Repository: magefree/mage (2026-04-16T01:11:14Z)

Issue:
xmage - game error with Estrid's Invocation's ability using for the second time
Estrid's Invocation causes a fatal error when using its ability in the second turn its on the battlefield. Please fix it, because I like to play this card a lot ;-)

Error type: SERVER - game error

Client version: 1.4.58-V1 (build: 2025-10-06 20:20)
Java version: 1.8.0_201
Default charset: UTF-8

Game end on critical error: mage.MageException: Error in unit tests

mage.MageException: Error in unit tests
Server version: 1.4.58-V1 (build: 2025-10-06 20:20)
Stack trace:
mage.game.GameImpl.playPriority(GameImpl.java:1816)
mage.game.turn.Step.priority(Step.java:73)
mage.game.turn.Phase.playStep(Phase.java:205)
mage.game.turn.Phase.play(Phase.java:91)
mage.game.turn.Turn.play(Turn.java:132)
mage.game.GameImpl.playTurn(GameImpl.java:1183)
mage.game.GameImpl.play(GameImpl.java:1090)
mage.game.GameImpl.start(GameImpl.java:1066)
mage.server.game.GameWorker.call(GameWorker.java:35)
mage.server.game.GameWorker.call(GameWorker.java:16)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:750)



Discussion:
Can't reproduce this on nightly.  Please try there and provide more information about the game state.

<img width="1582" height="993" alt="Image" src="https://github.com/user-attachments/assets/61124f73-9588-45f8-9faa-1ed0294ae87a" />
Assuming this has to do with copying Auras, reproduced a crash
```
INFO  2026-04-14 23:02:51,417 [LOG][GAME] T5.UP: PlayerA using choice: Yes (by setChoice, ability: Feather of Flight [01f]) =>[main] PrintGameLogsDataCollector.writeLog
INFO  2026-04-14 23:02:51,418 [LOG][GAME] T5.UP: PlayerA moves Estrid's Invocation [01f] from battlefield to the exile zone =>[main] PrintGameLogsDataCollector.writeLog
FATAL 2026-04-14 23:02:51,419 Game error: ce79e0f1-ab89-427e-9039-b19e0df96325 - Two Player Duel; T5.UP; active: PlayerA; stack: 0 =>[main] GameImpl.playPriority
java.lang.IllegalArgumentException: Something wrong, found etb aura with empty spell ability or without any targets: Estrid's Invocation [01f] (CardImpl -> EstridsInvocation), source: At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control.
        at mage.players.PlayerImpl.moveCards(PlayerImpl.java:4973)
        at mage.players.PlayerImpl.moveCards(PlayerImpl.java:4927)
        at org.mage.test.player.TestPlayer.moveCards(TestPlayer.java:4466)
        at mage.cards.e.EstridsInvocationEffect.apply(EstridsInvocation.java:92)
        at mage.abilities.AbilityImpl.resolveMode(AbilityImpl.java:232)
        at mage.abilities.AbilityImpl.resolve(AbilityImpl.java:216)
        at mage.abilities.TriggeredAbilityImpl.resolve(TriggeredAbilityImpl.java:279)
        at mage.game.stack.StackAbility.resolve(StackAbility.java:85)
        at mage.game.GameImpl.resolve(GameImpl.java:1842)
        at mage.game.GameImpl.playPriority(GameImpl.java:1763)
        at mage.game.turn.Step.priority(Step.java:73)
        at mage.game.turn.Phase.playStep(Phase.java:205)
        at mage.game.turn.Phase.play(Phase.java:91)
        at mage.game.turn.Turn.play(Turn.java:132)
        at mage.game.GameImpl.playTurn(GameImpl.java:1180)
        at mage.game.GameImpl.play(GameImpl.java:1087)
        at mage.game.GameImpl.start(GameImpl.java:1063)
        at org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.execute(CardTestPlayerAPIImpl.java:324)
        at org.mage.test.cards.copy.EstridsInvocationTest.testCopyAura(EstridsInvocationTest.java:34)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
        at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
        at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
        at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
        at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
        at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56)
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184)
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148)
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:122)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
        at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
        at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
```



Patch:
diff --git a/Mage.Sets/src/mage/cards/e/EstridsInvocation.java b/Mage.Sets/src/mage/cards/e/EstridsInvocation.java
index edb6034826f3..8e3b6c93dd8a 100644
--- a/Mage.Sets/src/mage/cards/e/EstridsInvocation.java
+++ b/Mage.Sets/src/mage/cards/e/EstridsInvocation.java
@@ -6,11 +6,13 @@
 import mage.abilities.common.EntersBattlefieldAbility;
 import mage.abilities.effects.OneShotEffect;
 import mage.abilities.effects.common.CopyPermanentEffect;
+import mage.abilities.effects.common.ExileAndReturnSourceEffect;
 import mage.cards.Card;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
 import mage.constants.CardType;
 import mage.constants.Outcome;
+import mage.constants.PutCards;
 import mage.constants.Zone;
 import mage.filter.FilterPermanent;
 import mage.filter.common.FilterControlledEnchantmentPermanent;
@@ -58,38 +60,8 @@ class EstridsInvocationCopyApplier extends CopyApplier {
     public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) {
         // At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control.
         blueprint.getAbilities().add(new BeginningOfUpkeepTriggeredAbility(
-                new EstridsInvocationEffect(), true
+                new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD), true
         ));
         return true;
     }
 }
-
-class EstridsInvocationEffect extends OneShotEffect {
-
-    EstridsInvocationEffect() {
-        super(Outcome.Neutral);
-        this.staticText = "exile this enchantment. If you do, return it to the battlefield under its owner's control";
-    }
-
-    private EstridsInvocationEffect(final EstridsInvocationEffect effect) {
-        super(effect);
-    }
-
-    @Override
-    public EstridsInvocationEffect copy() {
-        return new EstridsInvocationEffect(this);
-    }
-
-    @Override
-    public boolean apply(Game game, Ability source) {
-        Player player = game.getPlayer(source.getControllerId());
-        Permanent permanent = source.getSourcePermanentIfItStillExists(game);
-        if (permanent == null || player == null) {
-            return false;
-        }
-        Card card = permanent.getMainCard();
-        player.moveCards(permanent, Zone.EXILED, source, game);
-        player.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null);
-        return true;
-    }
-}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java
index 1e8b2c1c4e9d..0a93d0c03515 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java
@@ -70,6 +70,7 @@ public boolean apply(Game game, Ability source) {
             return true;
         }
         controller.moveCards(permanent, Zone.EXILED, source, game);
+        game.processAction();
         putCards.moveCard(
                 returnUnderYourControl ? controller : game.getPlayer(permanent.getOwnerId()),
                 permanent.getMainCard(), source, game, "card"


Test patch:
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EstridsInvocationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EstridsInvocationTest.java
new file mode 100644
index 000000000000..751f5dd490f0
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EstridsInvocationTest.java
@@ -0,0 +1,42 @@
+package org.mage.test.cards.copy;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+public class EstridsInvocationTest extends CardTestPlayerBase {
+
+    @Test
+    public void testCopyAura() {
+        addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears");
+        addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears");
+        addCard(Zone.BATTLEFIELD, playerA, "Bear Cub");
+        addCard(Zone.HAND, playerA, "Estrid's Invocation");
+        addCard(Zone.HAND, playerA, "Feather of Flight");
+        addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
+        addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
+        addCard(Zone.BATTLEFIELD, playerA, "Impact Tremors");
+
+        castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Feather of Flight");
+        addTarget(playerA, "Balduvian Bears");
+
+        castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Estrid's Invocation");
+        setChoice(playerA, true);
+        setChoice(playerA, "Feather of Flight");
+        setChoice(playerA, "Bear Cub");
+        setChoice(playerA, true);
+        setChoice(playerA, true);
+        setChoice(playerA, "Feather of Flight");
+        setChoice(playerA, "Grizzly Bears");
+
+        setStrictChooseMode(true);
+        setStopAt(5, PhaseStep.PRECOMBAT_MAIN);
+        execute();
+
+        assertPowerToughness(playerA, "Balduvian Bears", 3, 2);
+        assertPowerToughness(playerA, "Grizzly Bears", 3, 2);
+        assertPowerToughness(playerA, "Bear Cub", 2, 2);
+    }
+
+}