diff --git a/compiler/GHC/StgToJS/Prim.hs b/compiler/GHC/StgToJS/Prim.hs
index dcd360b0d4988d2e0606949190f9d304a27e3723..414b7251acf3931b7b3ae8dd768a7ad0cc38d3c5 100644
--- a/compiler/GHC/StgToJS/Prim.hs
+++ b/compiler/GHC/StgToJS/Prim.hs
@@ -1348,23 +1348,27 @@ write_boff_addr a i r o = mconcat
 
 read_stableptr :: JStgExpr -> JStgExpr -> JStgExpr -> JStgExpr -> JStgStat
 read_stableptr a i r o = mconcat
-  [ r |= var "h$stablePtrBuf" -- stable pointers are always in this array
-  , o |= read_i32 a i
+  [ o |= read_i32 a i
+  , ifS (o .===. zero_)
+      (r |= null_)
+      (r |= var "h$stablePtrBuf")
   ]
 
 read_boff_stableptr :: JStgExpr -> JStgExpr -> JStgExpr -> JStgExpr -> JStgStat
 read_boff_stableptr a i r o = mconcat
-  [ r |= var "h$stablePtrBuf" -- stable pointers are always in this array
-  , o |= read_boff_i32 a i
+  [ o |= read_boff_i32 a i
+  , ifS (o .===. zero_)
+      (r |= null_)
+      (r |= var "h$stablePtrBuf")
   ]
 
 write_stableptr :: JStgExpr -> JStgExpr -> JStgExpr -> JStgExpr -> JStgStat
 write_stableptr a i _r o = write_i32 a i o
-  -- don't store "r" as it must be h$stablePtrBuf
+  -- don't store "r" as it must be h$stablePtrBuf or null
 
 write_boff_stableptr :: JStgExpr -> JStgExpr -> JStgExpr -> JStgExpr -> JStgStat
 write_boff_stableptr a i _r o = write_boff_i32 a i o
-  -- don't store "r" as it must be h$stablePtrBuf
+  -- don't store "r" as it must be h$stablePtrBuf or null
 
 write_u8 :: JStgExpr -> JStgExpr -> JStgExpr -> JStgStat
 write_u8 a i v = idx_u8 a i |= v
diff --git a/rts/js/stableptr.js b/rts/js/stableptr.js
index 82fc2d336c8ba52fc761cb6a05646d27204431f2..7912137ef0aded69bbaf50d24b58aa5f0f1ed05d 100644
--- a/rts/js/stableptr.js
+++ b/rts/js/stableptr.js
@@ -18,6 +18,13 @@ var h$stablePtrData = [null];
 var h$stablePtrBuf  = h$newByteArray(8);
 var h$stablePtrN    = 1;
 var h$stablePtrFree = [];
+// Slot 0 isn't used as offset 0 is reserved for the null pointer. In
+// particular, when we store a StablePtr in an array, we don't store the array
+// part. When we read it back, we only have the offset. Some codes initialize
+// these stored StablePtr with NULL (hence offset 0) and if we were creating a
+// StablePtr from it (i.e. [$stablePtrBuf,0]) then we can't compare them to
+// nullPtr (castStablePtrToPtr [$stablePtrBuf,0] /= [null,0]).
+// This happens in direct-sqlite package for example.
 
 function h$makeStablePtr(v) {
   TRACE_STABLEPTR("makeStablePtr")