diff --git a/router/java/src/net/i2p/router/OutNetMessage.java b/router/java/src/net/i2p/router/OutNetMessage.java
index 59dbcaef6015932ee133feb4a1e284e9a5a01189..8b30efe44bfd0eb265a00eae59e28b44942daa21 100644
--- a/router/java/src/net/i2p/router/OutNetMessage.java
+++ b/router/java/src/net/i2p/router/OutNetMessage.java
@@ -12,10 +12,8 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.I2NPMessage;
@@ -42,7 +40,7 @@ public class OutNetMessage implements CDPQEntry {
     private ReplyJob _onReply;
     private Job _onFailedReply;
     private MessageSelector _replySelector;
-    private Set<String> _failedTransports;
+    private List<String> _failedTransports;
     private long _sendBegin;
     //private Exception _createdBy;
     private final long _created;
@@ -280,14 +278,33 @@ public class OutNetMessage implements CDPQEntry {
     public MessageSelector getReplySelector() { return _replySelector; }
     public void setReplySelector(MessageSelector selector) { _replySelector = selector; }
     
-    public synchronized void transportFailed(String transportStyle) { 
-        if (_failedTransports == null)
-            _failedTransports = new HashSet<String>(2);
+    /**
+     * As of 0.9.55, returns the previous number of failed transports.
+     */
+    public synchronized int transportFailed(String transportStyle) { 
+        int rv;
+        if (_failedTransports == null) {
+            _failedTransports = new ArrayList<String>(2);
+            rv = 0;
+        } else {
+            rv = _failedTransports.size();
+        }
         _failedTransports.add(transportStyle); 
+        return rv;
+    }
+
+    /**
+     * @since 0.9.55
+     */
+    public synchronized int getFailedTransportCount() { 
+        return (_failedTransports == null ? 0 : _failedTransports.size()); 
     }
 
-    public synchronized Set<String> getFailedTransports() { 
-        return (_failedTransports == null ? Collections.<String> emptySet() : _failedTransports); 
+    /**
+     * As of 0.9.55, changed from a Set to a List
+     */
+    public synchronized List<String> getFailedTransports() { 
+        return (_failedTransports == null ? Collections.<String>emptyList() : _failedTransports); 
     }
     
     /** when did the sending process begin */
diff --git a/router/java/src/net/i2p/router/transport/GetBidsJob.java b/router/java/src/net/i2p/router/transport/GetBidsJob.java
index 1471adeca01c82a02b7a95173ec03c3eaf75a009..3792d5367910191b6a5f282fb364da9a2b66b7fe 100644
--- a/router/java/src/net/i2p/router/transport/GetBidsJob.java
+++ b/router/java/src/net/i2p/router/transport/GetBidsJob.java
@@ -43,6 +43,11 @@ class GetBidsJob extends JobImpl {
     }
     
     static void getBids(RouterContext context, TransportManager tmgr, OutNetMessage msg) {
+        if (msg.getFailedTransportCount() > 1) {
+            context.statManager().addRateData("transport.bidFailAllTransports", msg.getLifetime());
+            fail(context, msg);
+            return;
+        }
         Log log = context.logManager().getLog(GetBidsJob.class);
         Hash to = msg.getTarget().getIdentity().getHash();
         msg.timestamp("bid");
@@ -67,15 +72,13 @@ class GetBidsJob extends JobImpl {
         
         TransportBid bid = tmgr.getNextBid(msg);
         if (bid == null) {
-            int failedCount = msg.getFailedTransports().size();
+            int failedCount = msg.getFailedTransportCount();
             if (failedCount == 0) {
                 context.statManager().addRateData("transport.bidFailNoTransports", msg.getLifetime());
                 // This used to be "no common transports" but it is almost always no transports at all
                 context.banlist().banlistRouter(to, _x("No transports (hidden or starting up?)"));
             } else if (failedCount >= tmgr.getTransportCount()) {
                 context.statManager().addRateData("transport.bidFailAllTransports", msg.getLifetime());
-                // fail after all transports were unsuccessful
-                context.netDb().fail(to);
             }
             fail(context, msg);
         } else {
diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java
index d5c70a027642d2eba982176b26ec794e0fca47c1..6f591fe3250cc5f282712fa18e9750bfe0bc91a7 100644
--- a/router/java/src/net/i2p/router/transport/TransportImpl.java
+++ b/router/java/src/net/i2p/router/transport/TransportImpl.java
@@ -310,8 +310,13 @@ public abstract class TransportImpl implements Transport {
         else
             msg.timestamp("afterSend(failed)");
 
-        if (!sendSuccessful)
-            msg.transportFailed(getStyle());
+        if (!sendSuccessful) {
+            int prev = msg.transportFailed(getStyle());
+            // This catches the usual case with two enabled transports
+            // GetBidsJob will check against actual transport count
+            if (prev > 0)
+                allowRequeue = false;
+        }
 
         if (msToSend > 1500) {
             if (debug)
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index 44c6a8970b95d88c600cf9c9eff16e3ff7358fe5..7b1a0da1ae11d85c103f7729adb7bed48a05c445 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -847,7 +847,7 @@ public class TransportManager implements TransportEventListener {
             throw new IllegalArgumentException("Bids for a message bound to ourselves?");
 
         List<TransportBid> rv = new ArrayList<TransportBid>(_transports.size());
-        Set<String> failedTransports = msg.getFailedTransports();
+        List<String> failedTransports = msg.getFailedTransports();
         for (Transport t : _transports.values()) {
             if (failedTransports.contains(t.getStyle())) {
                 if (_log.shouldLog(Log.DEBUG))
@@ -873,7 +873,7 @@ public class TransportManager implements TransportEventListener {
     TransportBid getNextBid(OutNetMessage msg) {
         int unreachableTransports = 0;
         Hash peer = msg.getTarget().getIdentity().calculateHash();
-        Set<String> failedTransports = msg.getFailedTransports();
+        List<String> failedTransports = msg.getFailedTransports();
         TransportBid rv = null;
         for (Transport t : _transports.values()) {
             if (t.isUnreachable(peer)) {