diff --git a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java
index ef81a92d265083086479aaf922a3aeaa902af802..f0e01fc4926dc5d5a021890e0b2cee69d768e85c 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java
@@ -89,6 +89,8 @@ public class GraphHelper extends FormHandler {
     public void setPersistent(String foo) { _persistent = true; }
     
     public String getImages() { 
+        if (StatSummarizer.instance().isDisabled())
+            return "";
         try {
             List listeners = StatSummarizer.instance().getListeners();
             TreeSet ordered = new TreeSet(new AlphaComparator());
@@ -155,6 +157,8 @@ public class GraphHelper extends FormHandler {
     private static final int[] times = { 60, 2*60, 5*60, 10*60, 30*60, 60*60, -1 };
 
     public String getForm() { 
+        if (StatSummarizer.instance().isDisabled())
+            return "";
         String prev = System.getProperty("net.i2p.router.web.GraphHelper.nonce");
         if (prev != null) System.setProperty("net.i2p.router.web.GraphHelper.noncePrev", prev);
         String nonce = "" + _context.random().nextLong();
@@ -198,6 +202,27 @@ public class GraphHelper extends FormHandler {
         return ""; 
     }
 
+    /**
+     *  We have to do this here because processForm() isn't called unless the nonces are good
+     *  @since 0.8.6
+     */
+    @Override
+    public String getAllMessages() {
+        if (StatSummarizer.instance().isDisabled()) {
+            addFormError("Graphing not supported with this JVM: " +
+                         System.getProperty("java.vendor") + ' ' +
+                         System.getProperty("java.version") + " (" +
+                         System.getProperty("java.runtime.name") + ' ' +
+                         System.getProperty("java.runtime.version") + ')');
+            if (_context.getProperty(PROP_REFRESH, 0) >= 0) {
+                // force no refresh, save silently
+                _context.router().setConfigSetting(PROP_REFRESH, "-1");
+                _context.router().saveConfig();
+            }
+        }
+        return super.getAllMessages();
+    }
+
     /**
      *  This was a HelperBase but now it's a FormHandler
      *  @since 0.8.2
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java
index 431696296eaee99d0c4799ede6c1dc2ea82a9dde..26e5f246394417d053f3f974701d9698ad82b6e7 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java
@@ -48,6 +48,7 @@ public class StatSummarizer implements Runnable {
     private static final int MAX_CONCURRENT_PNG = 3;
     private final Semaphore _sem;
     private volatile boolean _isRunning = true;
+    private volatile boolean _isDisabled;
     private Thread _thread;
     
     public StatSummarizer() {
@@ -62,6 +63,20 @@ public class StatSummarizer implements Runnable {
     public static StatSummarizer instance() { return _instance; }
     
     public void run() {
+        // JRobin 1.5.9 crashes these JVMs
+        String vendor = System.getProperty("java.vendor");
+        if (vendor.startsWith("Apache") ||                      // Harmony
+            vendor.startsWith("GNU Classpath") ||               // JamVM
+            vendor.startsWith("Free Software Foundation")) {    // gij
+            _log.logAlways(Log.WARN, "Graphing not supported with this JVM: " +
+                                     vendor + ' ' +
+                                     System.getProperty("java.version") + " (" +
+                                     System.getProperty("java.runtime.name") + ' ' +
+                                     System.getProperty("java.runtime.version") + ')');
+            _isDisabled = true;
+            _isRunning = false;
+            return;
+        }
         boolean isPersistent = _context.getBooleanPropertyDefaultTrue(SummaryListener.PROP_PERSISTENT);
         if (!isPersistent)
             deleteOldRRDs();
@@ -73,6 +88,11 @@ public class StatSummarizer implements Runnable {
         }
     }
     
+    /** @since 0.8.6 */
+    boolean isDisabled() {
+        return _isDisabled;
+    }
+
     /** list of SummaryListener instances */
     List<SummaryListener> getListeners() { return _listeners; }
     
@@ -142,8 +162,11 @@ public class StatSummarizer implements Runnable {
     }
     private void addDb(Rate r) {
         SummaryListener lsnr = new SummaryListener(r);
-        _listeners.add(lsnr);
-        lsnr.startListening();
+        boolean success = lsnr.startListening();
+        if (success)
+            _listeners.add(lsnr);
+        else
+            _log.error("Failed to add RRD for rate " + r.getRateStat().getName() + '.' + r.getPeriod());
         //System.out.println("Start listening for " + r.getRateStat().getName() + ": " + r.getPeriod());
     }
 
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java
index b5721ff5fe0f8f0933ec66c0b3338b6dc0003210..3b48833c7f9032e7e7543e63e0c8deb5a3880f29 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java
@@ -104,7 +104,10 @@ class SummaryListener implements RateSummaryListener {
     
     public Rate getRate() { return _rate; }
 
-    public void startListening() {
+    /**
+     *  @return success
+     */
+    public boolean startListening() {
         RateStat rs = _rate.getRateStat();
         long period = _rate.getPeriod();
         String baseName = rs.getName() + "." + period;
@@ -156,11 +159,15 @@ class SummaryListener implements RateSummaryListener {
             _sample = _db.createSample();
             _renderer = new SummaryRenderer(_context, this);
             _rate.setSummaryListener(this);
+            return true;
+        } catch (OutOfMemoryError oom) {
+            _log.error("Error starting RRD for stat " + baseName, oom);
         } catch (RrdException re) {
-            _log.error("Error starting", re);
+            _log.error("Error starting RRD for stat " + baseName, re);
         } catch (IOException ioe) {
-            _log.error("Error starting", ioe);
+            _log.error("Error starting RRD for stat " + baseName, ioe);
         }
+        return false;
     }
 
     public void stopListening() {
@@ -181,10 +188,16 @@ class SummaryListener implements RateSummaryListener {
     }
 
     public void renderPng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException {
+        if (_renderer == null || _db == null)
+            throw new IOException("No RRD, check logs for previous errors");
         _renderer.render(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit); 
     }
 
-    public void renderPng(OutputStream out) throws IOException { _renderer.render(out); }
+    public void renderPng(OutputStream out) throws IOException {
+        if (_renderer == null || _db == null)
+            throw new IOException("No RRD, check logs for previous errors");
+        _renderer.render(out);
+    }
  
     String getName() { return _name; }