diff --git a/libinterp/corefcn/Cell.cc b/libinterp/corefcn/Cell.cc
index d5fb636..3ac9d63 100644
--- a/libinterp/corefcn/Cell.cc
+++ b/libinterp/corefcn/Cell.cc
@@ -162,51 +162,64 @@ Cell::index (const octave_value_list& idx_arg, bool resize_ok) const
 
   octave_idx_type n = idx_arg.length ();
 
-  switch (n)
-    {
-    case 0:
-      retval = *this;
-      break;
-
-    case 1:
-      {
-        idx_vector i = idx_arg(0).index_vector ();
-
-        if (! error_state)
-          retval = Array<octave_value>::index (i, resize_ok, Matrix ());
-      }
-      break;
-
-    case 2:
-      {
-        idx_vector i = idx_arg(0).index_vector ();
-
-        if (! error_state)
-          {
-            idx_vector j = idx_arg(1).index_vector ();
-
-            if (! error_state)
-              retval = Array<octave_value>::index (i, j, resize_ok, Matrix ());
-          }
-      }
-      break;
-
-    default:
-      {
-        Array<idx_vector> iv (dim_vector (n, 1));
-
-        for (octave_idx_type i = 0; i < n; i++)
-          {
-            iv(i) = idx_arg(i).index_vector ();
-
-            if (error_state)
-              break;
-          }
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-        if (!error_state)
-          retval = Array<octave_value>::index (iv, resize_ok, Matrix ());
-      }
-      break;
+  try
+    {
+      switch (n)
+	{
+	case 0:
+	  retval = *this;
+	  break;
+
+	case 1:
+	  {
+	    idx_vector i = idx_arg(0).index_vector ();
+
+	    if (! error_state)
+	      retval = Array<octave_value>::index (i, resize_ok, Matrix ());
+	  }
+	  break;
+
+	case 2:
+	  {
+	    idx_vector i = idx_arg(0).index_vector ();
+
+	    if (! error_state)
+	      {
+	        k = 1;
+		idx_vector j = idx_arg(1).index_vector ();
+
+		if (! error_state)
+		  retval = Array<octave_value>::index (i, j, resize_ok, Matrix ());
+	      }
+	  }
+	  break;
+
+	default:
+	  {
+	    Array<idx_vector> iv (dim_vector (n, 1));
+
+	    for (k = 0; k < n; k++)
+	      {
+		iv(k) = idx_arg(k).index_vector ();
+
+		if (error_state)
+		  break;
+	      }
+	    if (!error_state)
+	      retval = Array<octave_value>::index (iv, resize_ok, Matrix ());
+	  }
+	  break;
+	}
+    }
+  catch (idx_except& e)
+    {
+      e.set_pos_if_unset (n, k+1);
+      throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 
   return retval;
@@ -228,7 +241,17 @@ Cell::assign (const octave_value_list& idx_arg, const Cell& rhs,
   Array<idx_vector> ra_idx (dim_vector (len, 1));
 
   for (octave_idx_type i = 0; i < len; i++)
-    ra_idx(i) = idx_arg(i).index_vector ();
+    {
+      try
+        {
+          ra_idx(i) = idx_arg(i).index_vector ();
+        }
+      catch (idx_except& e)
+        {
+	  e.set_pos (len, i+1);
+	  throw;		// to be caught in pt-idx.cc  or  pt-assign.cc
+        }
+    }
 
   Array<octave_value>::assign (ra_idx, rhs, fill_val);
 }
@@ -242,7 +265,15 @@ Cell::delete_elements (const octave_value_list& idx_arg)
   Array<idx_vector> ra_idx (dim_vector (len, 1));
 
   for (octave_idx_type i = 0; i < len; i++)
-    ra_idx.xelem (i) = idx_arg(i).index_vector ();
+    try
+      {
+	ra_idx.xelem (i) = idx_arg(i).index_vector ();
+      }
+    catch (idx_except& e)
+        {
+	  e.set_pos (len, i+1);
+	  throw;		// to be caught in pt-idx.cc  or  pt-assign.cc
+        }
 
   Array<octave_value>::delete_elements (ra_idx);
 }
diff --git a/libinterp/corefcn/data.cc b/libinterp/corefcn/data.cc
index c132ba4..3ae184e 100644
--- a/libinterp/corefcn/data.cc
+++ b/libinterp/corefcn/data.cc
@@ -7169,44 +7169,51 @@ the ratio K/M is small; otherwise, it may be better to use @code{sort}.\n\
       if (dim < 0)
         dim = argx.dims ().first_non_singleton ();
 
-      idx_vector n = args(1).index_vector ();
+      try
+        {
+          idx_vector n = args(1).index_vector ();
 
-      if (error_state)
-        return retval;
+          if (error_state)
+            return retval;
 
-      switch (argx.builtin_type ())
-        {
-        case btyp_double:
-          retval = argx.array_value ().nth_element (n, dim);
-          break;
-        case btyp_float:
-          retval = argx.float_array_value ().nth_element (n, dim);
-          break;
-        case btyp_complex:
-          retval = argx.complex_array_value ().nth_element (n, dim);
-          break;
-        case btyp_float_complex:
-          retval = argx.float_complex_array_value ().nth_element (n, dim);
-          break;
+          switch (argx.builtin_type ())
+            {
+            case btyp_double:
+              retval = argx.array_value ().nth_element (n, dim);
+              break;
+            case btyp_float:
+              retval = argx.float_array_value ().nth_element (n, dim);
+              break;
+            case btyp_complex:
+              retval = argx.complex_array_value ().nth_element (n, dim);
+              break;
+            case btyp_float_complex:
+              retval = argx.float_complex_array_value ().nth_element (n, dim);
+              break;
 #define MAKE_INT_BRANCH(X) \
-        case btyp_ ## X: \
-          retval = argx.X ## _array_value ().nth_element (n, dim); \
-          break;
+            case btyp_ ## X: \
+              retval = argx.X ## _array_value ().nth_element (n, dim); \
+              break;
 
-        MAKE_INT_BRANCH (int8);
-        MAKE_INT_BRANCH (int16);
-        MAKE_INT_BRANCH (int32);
-        MAKE_INT_BRANCH (int64);
-        MAKE_INT_BRANCH (uint8);
-        MAKE_INT_BRANCH (uint16);
-        MAKE_INT_BRANCH (uint32);
-        MAKE_INT_BRANCH (uint64);
+            MAKE_INT_BRANCH (int8);
+            MAKE_INT_BRANCH (int16);
+            MAKE_INT_BRANCH (int32);
+            MAKE_INT_BRANCH (int64);
+            MAKE_INT_BRANCH (uint8);
+            MAKE_INT_BRANCH (uint16);
+            MAKE_INT_BRANCH (uint32);
+            MAKE_INT_BRANCH (uint64);
 #undef MAKE_INT_BRANCH
-        default:
-          if (argx.is_cellstr ())
-            retval = argx.cellstr_value ().nth_element (n, dim);
-          else
-            gripe_wrong_type_arg ("nth_element", argx);
+            default:
+              if (argx.is_cellstr ())
+                retval = argx.cellstr_value ().nth_element (n, dim);
+              else
+                gripe_wrong_type_arg ("nth_element", argx);
+            }
+        }
+      catch (idx_except& e)
+        {
+          error ("nth_element: invalid N value %s. %s", e.idx (), e.explain ());
         }
     }
   else
@@ -7248,42 +7255,50 @@ Undocumented internal function.\n\
   int nargin = args.length ();
   if (nargin >= 2 && nargin <= 3 && args(0).is_numeric_type ())
     {
-      idx_vector idx = args(0).index_vector ();
-      octave_idx_type n = -1;
-      if (nargin == 3)
-        n = args(2).idx_type_value (true);
-
-      if (! error_state)
+      try
         {
-          octave_value vals = args(1);
-          if (vals.is_range ())
-            {
-              Range r = vals.range_value ();
-              if (r.inc () == 0)
-                vals = r.base ();
-            }
+          idx_vector idx = args(0).index_vector ();
+          octave_idx_type n = -1;
+          if (nargin == 3)
+            n = args(2).idx_type_value (true);
 
-          if (vals.is_single_type ())
-            {
-              if (vals.is_complex_type ())
-                retval = do_accumarray_sum (idx,
-                                            vals.float_complex_array_value (),
-                                            n);
-              else
-                retval = do_accumarray_sum (idx, vals.float_array_value (), n);
-            }
-          else if (vals.is_numeric_type () || vals.is_bool_type ())
+          if (! error_state)
             {
-              if (vals.is_complex_type ())
-                retval = do_accumarray_sum (idx,
-                                            vals.complex_array_value (),
-                                            n);
+              octave_value vals = args(1);
+              if (vals.is_range ())
+                {
+                  Range r = vals.range_value ();
+                  if (r.inc () == 0)
+                    vals = r.base ();
+                }
+
+              if (vals.is_single_type ())
+                {
+                  if (vals.is_complex_type ())
+                    retval = do_accumarray_sum (idx,
+                                                vals.float_complex_array_value (),
+                                                n);
+                  else
+                    retval = do_accumarray_sum (idx, vals.float_array_value (), n);
+                }
+              else if (vals.is_numeric_type () || vals.is_bool_type ())
+                {
+                  if (vals.is_complex_type ())
+                    retval = do_accumarray_sum (idx,
+                                                vals.complex_array_value (),
+                                                n);
+                  else
+                    retval = do_accumarray_sum (idx, vals.array_value (), n);
+                }
               else
-                retval = do_accumarray_sum (idx, vals.array_value (), n);
+                gripe_wrong_type_arg ("accumarray", vals);
             }
-          else
-            gripe_wrong_type_arg ("accumarray", vals);
-        }
+          }
+        catch (idx_except& e)
+          {
+            error ("__accumarray_sum__: invalid IDX %s. %s",
+                                        e.idx(), e.explain ());
+          }
     }
   else
     print_usage ();
@@ -7328,60 +7343,69 @@ do_accumarray_minmax_fun (const octave_value_list& args,
   int nargin = args.length ();
   if (nargin >= 3 && nargin <= 4 && args(0).is_numeric_type ())
     {
-      idx_vector idx = args(0).index_vector ();
-      octave_idx_type n = -1;
-      if (nargin == 4)
-        n = args(3).idx_type_value (true);
-
-      if (! error_state)
+      try
         {
-          octave_value vals = args(1);
-          octave_value zero = args(2);
+          idx_vector idx = args(0).index_vector ();
+          octave_idx_type n = -1;
+          if (nargin == 4)
+            n = args(3).idx_type_value (true);
 
-          switch (vals.builtin_type ())
+          if (! error_state)
             {
-            case btyp_double:
-              retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin,
-                                             zero.double_value ());
-              break;
-            case btyp_float:
-              retval = do_accumarray_minmax (idx, vals.float_array_value (), n,
-                                             ismin, zero.float_value ());
-              break;
-            case btyp_complex:
-              retval = do_accumarray_minmax (idx, vals.complex_array_value (),
-                                             n, ismin, zero.complex_value ());
-              break;
-            case btyp_float_complex:
-              retval = do_accumarray_minmax (idx,
-                                             vals.float_complex_array_value (),
-                                             n, ismin,
-                                             zero.float_complex_value ());
-              break;
+              octave_value vals = args(1);
+              octave_value zero = args(2);
+
+              switch (vals.builtin_type ())
+                {
+                case btyp_double:
+                  retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin,
+                                                 zero.double_value ());
+                  break;
+                case btyp_float:
+                  retval = do_accumarray_minmax (idx, vals.float_array_value (), n,
+                                                 ismin, zero.float_value ());
+                  break;
+                case btyp_complex:
+                  retval = do_accumarray_minmax (idx, vals.complex_array_value (),
+                                                 n, ismin, zero.complex_value ());
+                  break;
+                case btyp_float_complex:
+                  retval = do_accumarray_minmax (idx,
+                                                 vals.float_complex_array_value (),
+                                                 n, ismin,
+                                                 zero.float_complex_value ());
+                  break;
 #define MAKE_INT_BRANCH(X) \
-            case btyp_ ## X: \
-              retval = do_accumarray_minmax (idx, vals.X ## _array_value (), \
-                                             n, ismin, \
-                                             zero.X ## _scalar_value ()); \
-              break;
+                case btyp_ ## X: \
+                  retval = do_accumarray_minmax (idx, vals.X ## _array_value (), \
+                                                 n, ismin, \
+                                                 zero.X ## _scalar_value ()); \
+                  break;
 
-            MAKE_INT_BRANCH (int8);
-            MAKE_INT_BRANCH (int16);
-            MAKE_INT_BRANCH (int32);
-            MAKE_INT_BRANCH (int64);
-            MAKE_INT_BRANCH (uint8);
-            MAKE_INT_BRANCH (uint16);
-            MAKE_INT_BRANCH (uint32);
-            MAKE_INT_BRANCH (uint64);
+                MAKE_INT_BRANCH (int8);
+                MAKE_INT_BRANCH (int16);
+                MAKE_INT_BRANCH (int32);
+                MAKE_INT_BRANCH (int64);
+                MAKE_INT_BRANCH (uint8);
+                MAKE_INT_BRANCH (uint16);
+                MAKE_INT_BRANCH (uint32);
+                MAKE_INT_BRANCH (uint64);
 #undef MAKE_INT_BRANCH
-            case btyp_bool:
-              retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin,
-                                             zero.bool_value ());
-              break;
-            default:
-              gripe_wrong_type_arg ("accumarray", vals);
+                case btyp_bool:
+                  retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin,
+                                                 zero.bool_value ());
+                  break;
+                default:
+                  gripe_wrong_type_arg ("accumarray", vals);
+                }
             }
         }
+      catch (idx_except& e)
+        {
+          error ("do_accumarray_minmax_fun: invalid index %s. %s",
+                                        e.idx (), e.explain ());
+        }
+
     }
   else
     print_usage ();
@@ -7448,39 +7472,46 @@ Undocumented internal function.\n\
   int nargin = args.length ();
   if (nargin >= 2 && nargin <= 4 && args(0).is_numeric_type ())
     {
-      idx_vector idx = args(0).index_vector ();
-      int dim = -1;
-      if (nargin >= 3)
-        dim = args(2).int_value () - 1;
-
-      octave_idx_type n = -1;
-      if (nargin == 4)
-        n = args(3).idx_type_value (true);
-
-      if (! error_state)
+      try
         {
-          octave_value vals = args(1);
+          idx_vector idx = args(0).index_vector ();
+          int dim = -1;
+          if (nargin >= 3)
+            dim = args(2).int_value () - 1;
 
-          if (vals.is_single_type ())
-            {
-              if (vals.is_complex_type ())
-                retval = do_accumdim_sum (idx,
-                                          vals.float_complex_array_value (),
-                                          dim, n);
-              else
-                retval = do_accumdim_sum (idx, vals.float_array_value (),
-                                          dim, n);
-            }
-          else if (vals.is_numeric_type () || vals.is_bool_type ())
+          octave_idx_type n = -1;
+          if (nargin == 4)
+            n = args(3).idx_type_value (true);
+
+          if (! error_state)
             {
-              if (vals.is_complex_type ())
-                retval = do_accumdim_sum (idx, vals.complex_array_value (),
-                                          dim, n);
+              octave_value vals = args(1);
+
+              if (vals.is_single_type ())
+                {
+                  if (vals.is_complex_type ())
+                    retval = do_accumdim_sum (idx,
+                                              vals.float_complex_array_value (),
+                                              dim, n);
+                  else
+                    retval = do_accumdim_sum (idx, vals.float_array_value (),
+                                              dim, n);
+                }
+              else if (vals.is_numeric_type () || vals.is_bool_type ())
+                {
+                  if (vals.is_complex_type ())
+                    retval = do_accumdim_sum (idx, vals.complex_array_value (),
+                                              dim, n);
+                  else
+                    retval = do_accumdim_sum (idx, vals.array_value (), dim, n);
+                }
               else
-                retval = do_accumdim_sum (idx, vals.array_value (), dim, n);
+                gripe_wrong_type_arg ("accumdim", vals);
             }
-          else
-            gripe_wrong_type_arg ("accumdim", vals);
+        }
+      catch (idx_except& e)
+        {
+          error ("__accumdim_sum__: invalid IDX %s. %s", e.idx(), e.explain ());
         }
     }
   else
diff --git a/libinterp/corefcn/find.cc b/libinterp/corefcn/find.cc
index b38d0c3..d9e47d0 100644
--- a/libinterp/corefcn/find.cc
+++ b/libinterp/corefcn/find.cc
@@ -456,6 +456,8 @@ b = sparse (i, j, v, sz(1), sz(2));\n\
           // This case is equivalent to extracting indices from a logical
           // matrix. Try to reuse the possibly cached index vector.
           retval(0) = arg.index_vector ().unmask ();
+          // No need to catch idx_except, since arg is bool.
+          // Out-of-range errors have already set pos, and will be caught later
         }
       else
         {
diff --git a/libinterp/corefcn/oct-map.cc b/libinterp/corefcn/oct-map.cc
index 8054b24..4dc726f 100644
--- a/libinterp/corefcn/oct-map.cc
+++ b/libinterp/corefcn/oct-map.cc
@@ -900,46 +900,60 @@ octave_map::index (const octave_value_list& idx, bool resize_ok) const
   octave_idx_type n_idx = idx.length ();
   octave_map retval;
 
-  switch (n_idx)
-    {
-    case 1:
-      {
-        idx_vector i = idx(0).index_vector ();
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-        if (! error_state)
-          retval = index (i, resize_ok);
-      }
-      break;
+  try
+    {
+      switch (n_idx)
+        {
+        case 1:
+          {
+            idx_vector i = idx(0).index_vector ();
 
-    case 2:
-      {
-        idx_vector i = idx(0).index_vector ();
+            if (! error_state)
+              retval = index (i, resize_ok);
+          }
+          break;
 
-        if (! error_state)
+        case 2:
           {
-            idx_vector j = idx(1).index_vector ();
+            idx_vector i = idx(0).index_vector ();
 
-            retval = index (i, j, resize_ok);
-          }
-      }
-      break;
+            if (! error_state)
+              {
+                k = 1;
+                idx_vector j = idx(1).index_vector ();
 
-    default:
-      {
-        Array<idx_vector> ia (dim_vector (n_idx, 1));
+                retval = index (i, j, resize_ok);
+              }
+          }
+          break;
 
-        for (octave_idx_type i = 0; i < n_idx; i++)
+        default:
           {
-            ia(i) = idx(i).index_vector ();
+            Array<idx_vector> ia (dim_vector (n_idx, 1));
 
-            if (error_state)
-              break;
-          }
+            for (k = 0; k < n_idx; k++)
+              {
+                ia(k) = idx(k).index_vector ();
+
+                if (error_state)
+                  break;
+              }
 
-        if (! error_state)
-          retval = index (ia, resize_ok);
-      }
-      break;
+            if (! error_state)
+              retval = index (ia, resize_ok);
+          }
+          break;
+        }
+    }
+  catch (idx_except& e)
+    {
+      e.set_pos_if_unset (n_idx, k+1);
+      throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 
   return retval;
@@ -1094,46 +1108,60 @@ octave_map::assign (const octave_value_list& idx, const octave_map& rhs)
 {
   octave_idx_type n_idx = idx.length ();
 
-  switch (n_idx)
-    {
-    case 1:
-      {
-        idx_vector i = idx(0).index_vector ();
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-        if (! error_state)
-          assign (i, rhs);
-      }
-      break;
+  try
+    {
+      switch (n_idx)
+        {
+        case 1:
+          {
+                idx_vector i = idx(0).index_vector ();
 
-    case 2:
-      {
-        idx_vector i = idx(0).index_vector ();
+                if (! error_state)
+                  assign (i, rhs);
+          }
+          break;
 
-        if (! error_state)
+        case 2:
           {
-            idx_vector j = idx(1).index_vector ();
+            idx_vector i = idx(0).index_vector ();
 
-            assign (i, j, rhs);
-          }
-      }
-      break;
+            if (! error_state)
+              {
+                k = 1;
+                idx_vector j = idx(1).index_vector ();
 
-    default:
-      {
-        Array<idx_vector> ia (dim_vector (n_idx, 1));
+                assign (i, j, rhs);
+              }
+          }
+          break;
 
-        for (octave_idx_type i = 0; i < n_idx; i++)
+        default:
           {
-            ia(i) = idx(i).index_vector ();
+            Array<idx_vector> ia (dim_vector (n_idx, 1));
 
-            if (error_state)
-              break;
-          }
+            for (k = 0; k < n_idx; k++)
+              {
+                ia(k) = idx(k).index_vector ();
+
+                if (error_state)
+                  break;
+              }
 
-        if (! error_state)
-          assign (ia, rhs);
-      }
-      break;
+            if (! error_state)
+              assign (ia, rhs);
+          }
+          break;
+        }
+    }
+  catch (idx_except& e)
+    {
+      e.set_pos_if_unset (n_idx, k+1);
+      throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 }
 
@@ -1244,7 +1272,15 @@ octave_map::delete_elements (const octave_value_list& idx)
 
   for (octave_idx_type i = 0; i < n_idx; i++)
     {
-      ia(i) = idx(i).index_vector ();
+      try
+        {
+          ia(i) = idx(i).index_vector ();
+        }
+      catch (idx_except& e)
+        {
+          e.set_pos_if_unset (n_idx, i+1);
+          throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
+        }
 
       if (error_state)
         break;
diff --git a/libinterp/corefcn/sparse.cc b/libinterp/corefcn/sparse.cc
index b5da61c..6f2b159 100644
--- a/libinterp/corefcn/sparse.cc
+++ b/libinterp/corefcn/sparse.cc
@@ -198,20 +198,30 @@ Compressed Column Sparse (rows = 3, cols = 4, nnz = 2 [17%])\n\
 
           if (! error_state)
             {
-              idx_vector i = args(0).index_vector ();
-              idx_vector j = args(1).index_vector ();
+              int k = 0;    // index we're checking when index_vector throws
+              try
+                {
+                  idx_vector i = args(0).index_vector ();
+                  k = 1;
+                  idx_vector j = args(1).index_vector ();
 
-              if (args(2).is_bool_type ())
-                retval = SparseBoolMatrix (args(2).bool_array_value (), i, j,
+                  if (args(2).is_bool_type ())
+                    retval = SparseBoolMatrix (args(2).bool_array_value (), i,j,
+                                               m, n, summation, nzmax);
+                  else if (args(2).is_complex_type ())
+                    retval = SparseComplexMatrix (args(2).complex_array_value(),
+                                                  i, j, m, n, summation, nzmax);
+                  else if (args(2).is_numeric_type ())
+                    retval = SparseMatrix (args(2).array_value (), i, j,
                                            m, n, summation, nzmax);
-              else if (args(2).is_complex_type ())
-                retval = SparseComplexMatrix (args(2).complex_array_value (),
-                                              i, j, m, n, summation, nzmax);
-              else if (args(2).is_numeric_type ())
-                retval = SparseMatrix (args(2).array_value (), i, j,
-                                       m, n, summation, nzmax);
-              else
-                gripe_wrong_type_arg ("sparse", args(2));
+                  else
+                    gripe_wrong_type_arg ("sparse", args(2));
+                }
+              catch (idx_except& e)
+                {
+                  e.set_pos_if_unset (2, k+1);
+                  throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
+                }
             }
 
         }
diff --git a/libinterp/corefcn/sub2ind.cc b/libinterp/corefcn/sub2ind.cc
index 8465a11..3b03d73 100644
--- a/libinterp/corefcn/sub2ind.cc
+++ b/libinterp/corefcn/sub2ind.cc
@@ -99,11 +99,21 @@ linear_index = sub2ind ([3, 3], 2, 3)\n\
             {
               if (args(j+1).is_numeric_type ())
                 {
-                  idxa(j) = args(j+1).index_vector ();
-                  if (error_state)
-                    break;
-                  else if (j > 0 && args(j+1).dims () != args(1).dims ())
-                    error ("sub2ind: all subscripts must be of the same size");
+                  try
+                    {
+                      idxa(j) = args(j+1).index_vector ();
+                      if (error_state)
+                        break;
+                      else if (j > 0 && args(j+1).dims () != args(1).dims ())
+                        error ("sub2ind: all subscripts must be of the same size");
+                    }
+                  catch (idx_except& e)
+                    {
+		      e.set_pos_if_unset (nargin-1, j+1);
+		      e.set_var ("");	  // no particular variable
+		      (*current_liboctave_error_with_id_handler)
+                                                        (e.id(), e.err());
+                    }
                 }
               else
                 error ("sub2ind: subscripts must be numeric");
@@ -134,23 +144,23 @@ linear_index = sub2ind ([3, 3], 2, 3)\n\
 
 # Test low index
 %!assert (sub2ind ([10 10 10], 1, 1, 1), 1)
-%!error <subscript indices> sub2ind ([10 10 10], 0, 1, 1)
-%!error <subscript indices> sub2ind ([10 10 10], 1, 0, 1)
-%!error <subscript indices> sub2ind ([10 10 10], 1, 1, 0)
+%!error <index \(0,_,_\)> sub2ind ([10 10 10], 0, 1, 1)
+%!error <index \(_,0,_\)> sub2ind ([10 10 10], 1, 0, 1)
+%!error <index \(_,_,0\)> sub2ind ([10 10 10], 1, 1, 0)
 
 # Test high index
 %!assert (sub2ind ([10 10 10], 10, 10, 10), 1000)
-%!error <index out of range> sub2ind ([10 10 10], 11, 10, 10)
-%!error <index out of range> sub2ind ([10 10 10], 10, 11, 10)
-%!error <index out of range> sub2ind ([10 10 10], 10, 10, 11)
+%!error <index \(11,_,_\); out of bound 10> sub2ind ([10 10 10], 11, 10, 10)
+%!error <index \(_,11,_\); out of bound 10> sub2ind ([10 10 10], 10, 11, 10)
+%!error <index \(_,_,11\); out of bound 10> sub2ind ([10 10 10], 10, 10, 11)
 
 # Test high index in the trailing dimensions
 %!assert (sub2ind ([10, 1], 2, 1, 1), 2)
-%!error <index out of range> sub2ind ([10, 1], 1, 2, 1)
-%!error <index out of range> sub2ind ([10, 1], 1, 1, 2)
+%!error <index \(_,2,_\); out of bound 1> sub2ind ([10, 1], 1, 2, 1)
+%!error <index \(_,_,2\); out of bound 1> sub2ind ([10, 1], 1, 1, 2)
 %!assert (sub2ind ([10 10], 2, 2, 1), 12)
-%!error <index out of range> sub2ind ([10 10], 2, 1, 2)
-%!error <index out of range> sub2ind ([10 10], 1, 2, 2)
+%!error <index \(_,_,2\); out of bound 1> sub2ind ([10 10], 2, 1, 2)
+%!error <index \(_,_,2\); out of bound 1> sub2ind ([10 10], 1, 2, 2)
 
 # Test handling of empty arguments
 %!assert (sub2ind ([10 10], zeros (0,0), zeros (0,0)), zeros (0,0))
@@ -164,8 +174,8 @@ linear_index = sub2ind ([3, 3], 2, 3)\n\
 
 ## Test input validation
 %!error <dimension vector> sub2ind ([10 10.5], 1, 1)
-%!error <subscript indices> sub2ind ([10 10], 1.5, 1)
-%!error <subscript indices> sub2ind ([10 10], 1, 1.5)
+%!error <index \(1.5,_\)> sub2ind ([10 10], 1.5, 1)
+%!error <index \(_,1.5\)> sub2ind ([10 10], 1, 1.5)
 */
 
 DEFUN (ind2sub, args, nargout,
@@ -195,14 +205,21 @@ moving from one column to next, filling up all rows in each column.\n\
   else
     {
       dim_vector dv = get_dim_vector (args(0), "ind2sub");
-      idx_vector idx = args(1).index_vector ();
-      if (! error_state)
+      try
         {
-          if (nargout > dv.length ())
-            dv = dv.redim (nargout);
+          idx_vector idx = args(1).index_vector ();
+          if (! error_state)
+            {
+              if (nargout > dv.length ())
+                dv = dv.redim (nargout);
 
-          Array<idx_vector> idxa = ind2sub (dv, idx);
-          retval = Array<octave_value> (idxa);
+              Array<idx_vector> idxa = ind2sub (dv, idx);
+              retval = Array<octave_value> (idxa);
+            }
+        }
+      catch (idx_except& e)
+        {
+          error ("ind2sub: Invalid index %s. %s", e.idx (), e.explain ());
         }
     }
 
diff --git a/libinterp/corefcn/toplev.cc b/libinterp/corefcn/toplev.cc
index ef869b7..ef7febe 100644
--- a/libinterp/corefcn/toplev.cc
+++ b/libinterp/corefcn/toplev.cc
@@ -643,6 +643,11 @@ main_loop (void)
           if (quitting_gracefully)
             return exit_status;
         }
+      catch (idx_except& e)
+        {
+          recover_from_exception ();
+	  std::cerr << "error: unhandled index exception: " << e.err() << std::endl << "-- trying to return to prompt" << std::endl;
+        }
       catch (octave_execution_exception)
         {
           recover_from_exception ();
diff --git a/libinterp/corefcn/utils.cc b/libinterp/corefcn/utils.cc
index 24263f9..78db431 100644
--- a/libinterp/corefcn/utils.cc
+++ b/libinterp/corefcn/utils.cc
@@ -1239,10 +1239,18 @@ dims_to_numel (const dim_vector& dims, const octave_value_list& idx)
             retval *= idxi.numel ();
           else
             {
-              idx_vector jdx = idxi.index_vector ();
-              if (error_state)
-                break;
-              retval *= jdx.length (dv(i));
+              try
+                {
+                  idx_vector jdx = idxi.index_vector ();
+                  if (error_state)
+                    break;
+                  retval *= jdx.length (dv(i));
+                }
+              catch (idx_except& e)
+                {
+                  error ("dims_to_numel: Invalid IDX %s. %s",
+                                                        e.idx (), e.explain ());
+                }
             }
         }
     }
diff --git a/libinterp/octave-value/ov-base-diag.cc b/libinterp/octave-value/ov-base-diag.cc
index f300304..6bf6bfe 100644
--- a/libinterp/octave-value/ov-base-diag.cc
+++ b/libinterp/octave-value/ov-base-diag.cc
@@ -29,6 +29,7 @@ along with Octave; see the file COPYING.  If not, see
 #include "mach-info.h"
 #include "lo-ieee.h"
 
+#include "ov-base-diag.h"
 #include "mxarray.h"
 #include "ov-base.h"
 #include "ov-base-mat.h"
@@ -103,26 +104,36 @@ octave_base_diag<DMT, MT>::do_index_op (const octave_value_list& idx,
 
   if (idx.length () == 2 && ! resize_ok)
     {
-      idx_vector idx0 = idx(0).index_vector ();
-      idx_vector idx1 = idx(1).index_vector ();
-
-      if (idx0.is_scalar () && idx1.is_scalar ())
-        {
-          retval = matrix.checkelem (idx0(0), idx1(0));
-        }
-      else
+      int k = 0;        // index we're accesing when index_vector throws
+      try
         {
-          octave_idx_type m = idx0.length (matrix.rows ());
-          octave_idx_type n = idx1.length (matrix.columns ());
-          if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n)
-              && m <= matrix.rows () && n <= matrix.rows ())
+          idx_vector idx0 = idx(0).index_vector ();
+          k = 1;
+          idx_vector idx1 = idx(1).index_vector ();
+
+          if (idx0.is_scalar () && idx1.is_scalar ())
             {
-              DMT rm (matrix);
-              rm.resize (m, n);
-              retval = rm;
+              retval = matrix.checkelem (idx0(0), idx1(0));
             }
           else
-            retval = to_dense ().do_index_op (idx, resize_ok);
+            {
+              octave_idx_type m = idx0.length (matrix.rows ());
+              octave_idx_type n = idx1.length (matrix.columns ());
+              if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n)
+                  && m <= matrix.rows () && n <= matrix.rows ())
+                {
+                  DMT rm (matrix);
+                  rm.resize (m, n);
+                  retval = rm;
+                }
+              else
+                retval = to_dense ().do_index_op (idx, resize_ok);
+            }
+        }
+      catch (idx_except& e)
+        {
+          e.set_pos_if_unset (2, k+1);
+          throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
         }
     }
   else
@@ -153,17 +164,27 @@ octave_base_diag<DMT, MT>::subsasgn (const std::string& type,
                 && jdx(0).is_scalar_type () && jdx(1).is_scalar_type ())
               {
                 typename DMT::element_type val;
-                idx_vector i0 = jdx(0).index_vector ();
-                idx_vector i1 = jdx(1).index_vector ();
-                if (! error_state  && i0(0) == i1(0)
-                    && i0(0) < matrix.rows () && i1(0) < matrix.cols ()
-                    && chk_valid_scalar (rhs, val))
+                int k = 0;
+                try
+                  {
+                    idx_vector i0 = jdx(0).index_vector ();
+                    k = 1;
+                    idx_vector i1 = jdx(1).index_vector ();
+                    if (! error_state  && i0(0) == i1(0)
+                        && i0(0) < matrix.rows () && i1(0) < matrix.cols ()
+                        && chk_valid_scalar (rhs, val))
+                      {
+                        matrix.dgelem (i0(0)) = val;
+                        retval = this;
+                        this->count++;
+                        // invalidate cache
+                        dense_cache = octave_value ();
+                      }
+                  }
+                catch (idx_except& e)
                   {
-                    matrix.dgelem (i0(0)) = val;
-                    retval = this;
-                    this->count++;
-                    // invalidate cache
-                    dense_cache = octave_value ();
+                    e.set_pos_if_unset (2, k+1);
+                    throw; // caught in pt-idx.cc / pt-assign.cc to get var name
                   }
               }
 
diff --git a/libinterp/octave-value/ov-base-mat.cc b/libinterp/octave-value/ov-base-mat.cc
index 9b0bcff..aad899f 100644
--- a/libinterp/octave-value/ov-base-mat.cc
+++ b/libinterp/octave-value/ov-base-mat.cc
@@ -36,7 +36,7 @@ along with Octave; see the file COPYING.  If not, see
 #include "ov-base-mat.h"
 #include "ov-base-scalar.h"
 #include "pr-output.h"
-
+ 
 template <class MT>
 octave_value
 octave_base_matrix<MT>::subsref (const std::string& type,
@@ -140,72 +140,86 @@ octave_base_matrix<MT>::do_index_op (const octave_value_list& idx,
   int nd = matrix.ndims ();
   const MT& cmatrix = matrix;
 
-  switch (n_idx)
-    {
-    case 0:
-      retval = matrix;
-      break;
-
-    case 1:
-      {
-        idx_vector i = idx (0).index_vector ();
-
-        if (! error_state)
-          {
-            // optimize single scalar index.
-            if (! resize_ok && i.is_scalar ())
-              retval = cmatrix.checkelem (i(0));
-            else
-              retval = MT (matrix.index (i, resize_ok));
-          }
-      }
-      break;
-
-    case 2:
-      {
-        idx_vector i = idx (0).index_vector ();
-
-        if (! error_state)
-          {
-            idx_vector j = idx (1).index_vector ();
-
-            if (! error_state)
-              {
-                // optimize two scalar indices.
-                if (! resize_ok && i.is_scalar () && j.is_scalar ())
-                  retval = cmatrix.checkelem (i(0), j(0));
-                else
-                  retval = MT (matrix.index (i, j, resize_ok));
-              }
-          }
-      }
-      break;
-
-    default:
-      {
-        Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
-        bool scalar_opt = n_idx == nd && ! resize_ok;
-        const dim_vector dv = matrix.dims ();
-
-        for (octave_idx_type i = 0; i < n_idx; i++)
-          {
-            idx_vec(i) = idx(i).index_vector ();
-
-            if (error_state)
-              break;
-
-            scalar_opt = (scalar_opt && idx_vec(i).is_scalar ());
-          }
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-        if (! error_state)
-          {
-            if (scalar_opt)
-              retval = cmatrix.checkelem (conv_to_int_array (idx_vec));
-            else
-              retval = MT (matrix.index (idx_vec, resize_ok));
-          }
-      }
-      break;
+  try
+    {
+      switch (n_idx)
+	{
+	case 0:
+	  retval = matrix;
+	  break;
+
+	case 1:
+	  {
+	    idx_vector i = idx (0).index_vector ();
+
+	    if (! error_state)
+	      {
+		// optimize single scalar index.
+		if (! resize_ok && i.is_scalar ())
+		  retval = cmatrix.checkelem (i(0));
+		else
+		  retval = MT (matrix.index (i, resize_ok));
+	      }
+	  }
+	  break;
+
+	case 2:
+	  {
+	    idx_vector i = idx (0).index_vector ();
+
+	    if (! error_state)
+	      {
+		k=1;
+		idx_vector j = idx (1).index_vector ();
+
+		if (! error_state)
+		  {
+		    // optimize two scalar indices.
+		    if (! resize_ok && i.is_scalar () && j.is_scalar ())
+		      retval = cmatrix.checkelem (i(0), j(0));
+		    else
+		      retval = MT (matrix.index (i, j, resize_ok));
+		  }
+	      }
+	  }
+	  break;
+
+	default:
+	  {
+	    Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
+	    bool scalar_opt = n_idx == nd && ! resize_ok;
+	    const dim_vector dv = matrix.dims ();
+
+	    for (k = 0; k < n_idx; k++)
+	      {
+		idx_vec(k) = idx(k).index_vector ();
+
+		if (error_state)
+		  break;
+
+		scalar_opt = (scalar_opt && idx_vec(k).is_scalar ());
+	      }
+
+	    if (! error_state)
+	      {
+		if (scalar_opt)
+		  retval = cmatrix.checkelem (conv_to_int_array (idx_vec));
+		else
+		  retval = MT (matrix.index (idx_vec, resize_ok));
+	      }
+	  }
+	  break;
+	}
+    }
+  catch (idx_except& e)
+    {
+      e.set_pos_if_unset (n_idx, k+1);
+      throw;   // to be caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 
   return retval;
@@ -217,51 +231,64 @@ octave_base_matrix<MT>::assign (const octave_value_list& idx, const MT& rhs)
 {
   octave_idx_type n_idx = idx.length ();
 
-  switch (n_idx)
-    {
-    case 0:
-      panic_impossible ();
-      break;
-
-    case 1:
-      {
-        idx_vector i = idx (0).index_vector ();
-
-        if (! error_state)
-          matrix.assign (i, rhs);
-      }
-      break;
-
-    case 2:
-      {
-        idx_vector i = idx (0).index_vector ();
-
-        if (! error_state)
-          {
-            idx_vector j = idx (1).index_vector ();
-
-            if (! error_state)
-              matrix.assign (i, j, rhs);
-          }
-      }
-      break;
-
-    default:
-      {
-        Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-        for (octave_idx_type i = 0; i < n_idx; i++)
-          {
-            idx_vec(i) = idx(i).index_vector ();
-
-            if (error_state)
-              break;
-          }
-
-        if (! error_state)
-          matrix.assign (idx_vec, rhs);
-      }
-      break;
+  try
+    {
+      switch (n_idx)
+	{
+	  case 0:
+	    panic_impossible ();
+	    break;
+
+	  case 1:
+	    {
+		  idx_vector i = idx (0).index_vector ();
+
+		  if (! error_state)
+		    matrix.assign (i, rhs);
+	    }
+	    break;
+
+	  case 2:
+	    {
+	      idx_vector i = idx (0).index_vector ();
+
+	      if (! error_state)
+		{
+		  k = 1;
+		  idx_vector j = idx (1).index_vector ();
+
+		  if (! error_state)
+		    matrix.assign (i, j, rhs);
+		}
+	    }
+	    break;
+
+	  default:
+	    {
+	      Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
+
+	      for (k = 0; k < n_idx; k++)
+		{
+		  idx_vec(k) = idx(k).index_vector ();
+
+		  if (error_state)
+		    break;
+		}
+
+	      if (! error_state)
+		matrix.assign (idx_vec, rhs);
+	    }
+	    break;
+	}
+    }
+  catch (idx_except& e)
+    {
+      gripe_invalid_index (e.idx(), n_idx, k+1);
     }
 
   // Clear cache.
@@ -284,89 +311,102 @@ octave_base_matrix<MT>::assign (const octave_value_list& idx,
 {
   octave_idx_type n_idx = idx.length ();
 
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
+
   int nd = matrix.ndims ();
 
   MT mrhs (dim_vector (1, 1), rhs);
 
-  switch (n_idx)
+  try
     {
-    case 0:
-      panic_impossible ();
-      break;
-
-    case 1:
-      {
-        idx_vector i = idx (0).index_vector ();
-
-        if (! error_state)
-          {
-            // optimize single scalar index.
-            if (i.is_scalar () && i(0) < matrix.numel ())
-              matrix(i(0)) = rhs;
-            else
-              matrix.assign (i, mrhs);
-          }
-      }
-      break;
-
-    case 2:
-      {
-        idx_vector i = idx (0).index_vector ();
-
-        if (! error_state)
-          {
-            idx_vector j = idx (1).index_vector ();
-
-            if (! error_state)
-              {
-                // optimize two scalar indices.
-                if (i.is_scalar () && j.is_scalar () && nd == 2
-                    && i(0) < matrix.rows () && j(0) < matrix.columns ())
-                  matrix(i(0), j(0)) = rhs;
-                else
-                  matrix.assign (i, j, mrhs);
-              }
-          }
-      }
-      break;
-
-    default:
-      {
-        Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
-        bool scalar_opt = n_idx == nd;
-        const dim_vector dv = matrix.dims ().redim (n_idx);
-
-        for (octave_idx_type i = 0; i < n_idx; i++)
-          {
-            idx_vec(i) = idx(i).index_vector ();
-
-            if (error_state)
-              break;
-
-            scalar_opt = (scalar_opt && idx_vec(i).is_scalar ()
-                          && idx_vec(i)(0) < dv(i));
-          }
-
-        if (! error_state)
-          {
-            if (scalar_opt)
-              {
-                // optimize all scalar indices. Don't construct an index array,
-                // but rather calc a scalar index directly.
-                octave_idx_type k = 1;
-                octave_idx_type j = 0;
-                for (octave_idx_type i = 0; i < n_idx; i++)
-                  {
-                    j += idx_vec(i)(0) * k;
-                    k *= dv (i);
-                  }
-                matrix(j) = rhs;
-              }
-            else
-              matrix.assign (idx_vec, mrhs);
-          }
-      }
-      break;
+      switch (n_idx)
+	{
+	case 0:
+	  panic_impossible ();
+	  break;
+
+	case 1:
+	  {
+	    idx_vector i = idx (0).index_vector ();
+
+	    if (! error_state)
+	      {
+		// optimize single scalar index.
+		if (i.is_scalar () && i(0) < matrix.numel ())
+		  matrix(i(0)) = rhs;
+		else
+		  matrix.assign (i, mrhs);
+	      }
+	  }
+	  break;
+
+	case 2:
+	  {
+	    idx_vector i = idx (0).index_vector ();
+
+	    if (! error_state)
+	      {
+	        k = 1;
+		idx_vector j = idx (1).index_vector ();
+
+		if (! error_state)
+		  {
+		    // optimize two scalar indices.
+		    if (i.is_scalar () && j.is_scalar () && nd == 2
+			&& i(0) < matrix.rows () && j(0) < matrix.columns ())
+		      matrix(i(0), j(0)) = rhs;
+		    else
+		      matrix.assign (i, j, mrhs);
+		  }
+	      }
+	  }
+	  break;
+
+	default:
+	  {
+	    Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
+	    bool scalar_opt = n_idx == nd;
+	    const dim_vector dv = matrix.dims ().redim (n_idx);
+
+	    for (k = 0; k < n_idx; k++)
+	      {
+		idx_vec(k) = idx(k).index_vector ();
+
+		if (error_state)
+		  break;
+
+		scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()
+			      && idx_vec(k)(0) < dv(k));
+	      }
+
+	    if (! error_state)
+	      {
+		if (scalar_opt)
+		  {
+		    // optimize all scalar indices. Don't construct
+		    // an index array, but rather calc a scalar index directly.
+		    octave_idx_type n = 1;
+		    octave_idx_type j = 0;
+		    for (octave_idx_type i = 0; i < n_idx; i++)
+		      {
+			j += idx_vec(i)(0) * n;
+			n *= dv (i);
+		      }
+		    matrix(j) = rhs;
+		  }
+		else
+		  matrix.assign (idx_vec, mrhs);
+	      }
+	  }
+	  break;
+	}
+    }
+  catch (idx_except& e)
+    {
+      gripe_invalid_index (e.idx(), n_idx, k+1);
     }
 
   // Clear cache.
diff --git a/libinterp/octave-value/ov-base-sparse.cc b/libinterp/octave-value/ov-base-sparse.cc
index e94babb..4543cf1 100644
--- a/libinterp/octave-value/ov-base-sparse.cc
+++ b/libinterp/octave-value/ov-base-sparse.cc
@@ -44,6 +44,8 @@ along with Octave; see the file COPYING.  If not, see
 #include "pager.h"
 #include "utils.h"
 
+#include "lo-array-gripes.h"
+
 template <class T>
 octave_value
 octave_base_sparse<T>::do_index_op (const octave_value_list& idx,
@@ -53,36 +55,50 @@ octave_base_sparse<T>::do_index_op (const octave_value_list& idx,
 
   octave_idx_type n_idx = idx.length ();
 
-  switch (n_idx)
-    {
-    case 0:
-      retval = matrix;
-      break;
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-    case 1:
-      {
-        idx_vector i = idx (0).index_vector ();
+  try
+    {
+      switch (n_idx)
+        {
+        case 0:
+          retval = matrix;
+          break;
 
-        if (! error_state)
-          retval = octave_value (matrix.index (i, resize_ok));
-      }
-      break;
+        case 1:
+          {
+            idx_vector i = idx (0).index_vector ();
 
-    case 2:
-      {
-        idx_vector i = idx (0).index_vector ();
+            if (! error_state)
+              retval = octave_value (matrix.index (i, resize_ok));
+          }
+          break;
 
-        if (! error_state)
+        case 2:
           {
-            idx_vector j = idx (1).index_vector ();
+            idx_vector i = idx (0).index_vector ();
 
             if (! error_state)
-              retval = octave_value (matrix.index (i, j, resize_ok));
+              {
+                k = 1;
+                idx_vector j = idx (1).index_vector ();
+
+                if (! error_state)
+                  retval = octave_value (matrix.index (i, j, resize_ok));
+              }
           }
-      }
-      break;
-    default:
-      error ("sparse indexing needs 1 or 2 indices");
+          break;
+        default:
+          error ("sparse indexing needs 1 or 2 indices");
+        }
+    }
+  catch (idx_except& e)
+    {
+      e.set_pos_if_unset (n_idx, k+1);
+      throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 
   return retval;
@@ -170,35 +186,48 @@ octave_base_sparse<T>::assign (const octave_value_list& idx, const T& rhs)
 
   octave_idx_type len = idx.length ();
 
-  switch (len)
-    {
-    case 1:
-      {
-        idx_vector i = idx (0).index_vector ();
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-        if (! error_state)
-          matrix.assign (i, rhs);
+  try
+    {
+      switch (len)
+        {
+        case 1:
+          {
+            idx_vector i = idx (0).index_vector ();
 
-        break;
-      }
+            if (! error_state)
+              matrix.assign (i, rhs);
 
-    case 2:
-      {
-        idx_vector i = idx (0).index_vector ();
+            break;
+          }
 
-        if (! error_state)
+        case 2:
           {
-            idx_vector j = idx (1).index_vector ();
+            idx_vector i = idx (0).index_vector ();
 
             if (! error_state)
-              matrix.assign (i, j, rhs);
-          }
+              {
+                k = 1;
+                idx_vector j = idx (1).index_vector ();
 
-        break;
-      }
+                if (! error_state)
+                  matrix.assign (i, j, rhs);
+              }
+            break;
+          }
 
-    default:
-      error ("sparse indexing needs 1 or 2 indices");
+        default:
+          error ("sparse indexing needs 1 or 2 indices");
+        }
+    }
+  catch (idx_except& e)
+    {
+      e.set_pos_if_unset (len, k+1);
+      throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 
 
@@ -212,35 +241,49 @@ octave_base_sparse<MT>::delete_elements (const octave_value_list& idx)
 {
   octave_idx_type len = idx.length ();
 
-  switch (len)
-    {
-    case 1:
-      {
-        idx_vector i = idx (0).index_vector ();
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
 
-        if (! error_state)
-          matrix.delete_elements (i);
+  try
+    {
+      switch (len)
+        {
+        case 1:
+          {
+            idx_vector i = idx (0).index_vector ();
 
-        break;
-      }
+            if (! error_state)
+              matrix.delete_elements (i);
 
-    case 2:
-      {
-        idx_vector i = idx (0).index_vector ();
+            break;
+          }
 
-        if (! error_state)
+        case 2:
           {
-            idx_vector j = idx (1).index_vector ();
+            idx_vector i = idx (0).index_vector ();
 
             if (! error_state)
-              matrix.delete_elements (i, j);
-          }
+              {
+                k = 1;
+                idx_vector j = idx (1).index_vector ();
 
-        break;
-      }
+                if (! error_state)
+                  matrix.delete_elements (i, j);
+              }
 
-    default:
-      error ("sparse indexing needs 1 or 2 indices");
+            break;
+          }
+
+        default:
+          error ("sparse indexing needs 1 or 2 indices");
+        }
+    }
+  catch (idx_except& e)
+    {
+      e.set_pos_if_unset (len, k+1);
+      throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 
   // Invalidate the matrix type
diff --git a/libinterp/octave-value/ov-base.cc b/libinterp/octave-value/ov-base.cc
index b1c2f8a..8dd1bf5 100644
--- a/libinterp/octave-value/ov-base.cc
+++ b/libinterp/octave-value/ov-base.cc
@@ -218,8 +218,8 @@ octave_base_value::do_multi_index_op (int nargout, const octave_value_list& idx,
 idx_vector
 octave_base_value::index_vector (bool /* require_integers */) const
 {
-  std::string nm = type_name ();
-  error ("%s type invalid as index value", nm.c_str ());
+  std::string nm = "<" + type_name () + ">";
+  gripe_invalid_index (nm.c_str ());
   return idx_vector ();
 }
 
diff --git a/libinterp/octave-value/ov-builtin.cc b/libinterp/octave-value/ov-builtin.cc
index d1aeb9e..6c76c16 100644
--- a/libinterp/octave-value/ov-builtin.cc
+++ b/libinterp/octave-value/ov-builtin.cc
@@ -143,6 +143,12 @@ octave_builtin::do_multi_index_op (int nargout, const octave_value_list& args,
 
           END_PROFILER_BLOCK
         }
+      catch (idx_except& e)	// temporary code.  Remove when confident
+        {			// all exceptions are caught.
+				// (Will fall through to next case anyway.)
+	  warning("error: unhandled index exception in ov-builtin");
+	  (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+        }
       catch (octave_execution_exception)
         {
           gripe_library_execution_error ();
diff --git a/libinterp/octave-value/ov-classdef.cc b/libinterp/octave-value/ov-classdef.cc
index 3468ec3..f526fac 100644
--- a/libinterp/octave-value/ov-classdef.cc
+++ b/libinterp/octave-value/ov-classdef.cc
@@ -1638,7 +1638,15 @@ cdef_object_array::subsref (const std::string& type,
 
         for (int i = 0; ! error_state && i < ival.length (); i++)
           {
-            iv(i) = ival(i).index_vector ();
+            try
+              {
+                iv(i) = ival(i).index_vector ();
+              }
+            catch (idx_except& e)
+              {
+                e.set_pos_if_unset (ival.length (), i+1);
+                throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
+              }
             if (! error_state)
               is_scalar = is_scalar && iv(i).is_scalar ();
           }
@@ -1736,7 +1744,15 @@ cdef_object_array::subsasgn (const std::string& type,
 
                   for (int i = 0; ! error_state && i < ival.length (); i++)
                     {
-                      iv(i) = ival(i).index_vector ();
+                      try
+                        {
+                          iv(i) = ival(i).index_vector ();
+                        }
+                      catch (idx_except& e)
+                        {
+                          e.set_pos_if_unset (ival.length (), i+1);
+                          throw;   // var name set in pt-idx.cc / pt-assign.cc
+                        }
                       if (! error_state)
                         is_scalar = is_scalar && iv(i).is_scalar ();
                     }
@@ -1789,7 +1805,15 @@ cdef_object_array::subsasgn (const std::string& type,
 
           for (int i = 0; ! error_state && i < ival.length (); i++)
             {
-              iv(i) = ival(i).index_vector ();
+              try
+                {
+                  iv(i) = ival(i).index_vector ();
+                }
+              catch (idx_except& e)
+                {
+                  e.set_pos_if_unset (ival.length (), i+1);
+                  throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
+                }
 
               if (! error_state)
                 {
diff --git a/libinterp/octave-value/ov-complex.cc b/libinterp/octave-value/ov-complex.cc
index 904514a..ff7666a 100644
--- a/libinterp/octave-value/ov-complex.cc
+++ b/libinterp/octave-value/ov-complex.cc
@@ -480,3 +480,28 @@ octave_complex::map (unary_mapper_t umap) const
       return octave_base_value::map (umap);
     }
 }
+
+/******************************************************************************/
+class complex_index : public idx_except
+{
+  virtual const char* explain() const
+  {
+    return ("subscripts must be real (forgot to initialize i or j?)");
+  }
+  virtual const char* id() const        // ID of error to throw
+  { return (error_id_invalid_index); }
+
+  public:
+  complex_index (const char *value) : idx_except (value) { }
+};
+
+// Complain if a complex value is used as a subscript
+void
+gripe_complex_index (Complex idx)
+{
+    char buf [100];
+    sprintf (buf, "%g%+gi", std::real(idx), std::imag(idx));
+
+    complex_index e(buf);
+    throw e;
+}
diff --git a/libinterp/octave-value/ov-complex.h b/libinterp/octave-value/ov-complex.h
index 6b63e2f..1a78857 100644
--- a/libinterp/octave-value/ov-complex.h
+++ b/libinterp/octave-value/ov-complex.h
@@ -43,6 +43,9 @@ class octave_value_list;
 
 class tree_walker;
 
+extern void OCTAVE_API
+gripe_complex_index (Complex idx);
+
 // Complex scalar values.
 
 class
@@ -81,8 +84,7 @@ public:
   // Use this to give a more specific error message
   idx_vector index_vector (bool /* require_integers */ = false) const
   {
-    error ("attempted to use a complex scalar as an index\n"
-           "       (forgot to initialize i or j?)");
+    gripe_complex_index (scalar);
     return idx_vector ();
   }
 
diff --git a/libinterp/octave-value/ov-java.cc b/libinterp/octave-value/ov-java.cc
index 81ba11c..17eca98 100644
--- a/libinterp/octave-value/ov-java.cc
+++ b/libinterp/octave-value/ov-java.cc
@@ -818,28 +818,34 @@ make_java_index (JNIEnv* jni_env, const octave_value_list& idx)
   jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, 0);
 
   for (int i = 0; i < idx.length (); i++)
-    {
-      idx_vector v = idx(i).index_vector ();
+    try
+      {
+        idx_vector v = idx(i).index_vector ();
 
-      if (! error_state)
-        {
-          jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ()));
-          jint *buf = jni_env->GetIntArrayElements (i_array, 0);
+        if (! error_state)
+          {
+            jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ()));
+            jint *buf = jni_env->GetIntArrayElements (i_array, 0);
 
-          for (int k = 0; k < v.length (); k++)
-            buf[k] = v(k);
+            for (int k = 0; k < v.length (); k++)
+              buf[k] = v(k);
 
-          jni_env->ReleaseIntArrayElements (i_array, buf, 0);
-          jni_env->SetObjectArrayElement (retval, i, i_array);
+            jni_env->ReleaseIntArrayElements (i_array, buf, 0);
+            jni_env->SetObjectArrayElement (retval, i, i_array);
 
-          check_exception (jni_env);
+            check_exception (jni_env);
 
-          if (error_state)
-            break;
-        }
-      else
-        break;
-    }
+            if (error_state)
+              break;
+          }
+        else
+          break;
+      }
+    catch (idx_except& e)
+      {
+        e.set_pos_if_unset (idx.length (), i+1);
+        throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
+      }
 
   return retval;
 }
diff --git a/libinterp/octave-value/ov-mex-fcn.cc b/libinterp/octave-value/ov-mex-fcn.cc
index 314fba6..0b6fd6a 100644
--- a/libinterp/octave-value/ov-mex-fcn.cc
+++ b/libinterp/octave-value/ov-mex-fcn.cc
@@ -153,6 +153,11 @@ octave_mex_function::do_multi_index_op (int nargout,
 
           END_PROFILER_BLOCK
         }
+      catch (idx_except& e)
+        {
+	  warning("error: unhandled index exception caught in ov-mex-fcn");
+	  (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+        }
       catch (octave_execution_exception)
         {
           gripe_library_execution_error ();
diff --git a/libinterp/octave-value/ov-perm.cc b/libinterp/octave-value/ov-perm.cc
index 8f2aefc..00bff72 100644
--- a/libinterp/octave-value/ov-perm.cc
+++ b/libinterp/octave-value/ov-perm.cc
@@ -74,8 +74,18 @@ octave_perm_matrix::do_index_op (const octave_value_list& idx,
   idx_vector idx0, idx1;
   if (nidx == 2)
     {
-      idx0 = idx(0).index_vector ();
-      idx1 = idx(1).index_vector ();
+      int k = 0;    // index we're processing when index_vector throws
+      try
+        {
+          idx0 = idx(0).index_vector ();
+          k = 1;
+          idx1 = idx(1).index_vector ();
+        }
+      catch (idx_except& e)
+        {
+          e.set_pos_if_unset (2, k+1);
+          throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
+        }
     }
 
   // This hack is to allow constructing permutation matrices using
diff --git a/libinterp/octave-value/ov-range.cc b/libinterp/octave-value/ov-range.cc
index 2d23848..9434c17 100644
--- a/libinterp/octave-value/ov-range.cc
+++ b/libinterp/octave-value/ov-range.cc
@@ -128,13 +128,21 @@ octave_range::do_index_op (const octave_value_list& idx, bool resize_ok)
       octave_value retval;
 
       // The range can handle a single subscript.
-      idx_vector i = idx(0).index_vector ();
-      if (! error_state)
+      try
         {
-          if (i.is_scalar () && i(0) < range.nelem ())
-            retval = range.elem (i(0));
-          else
-            retval = range.index (i);
+          idx_vector i = idx(0).index_vector ();
+	  if (! error_state)
+	    {
+	      if (i.is_scalar () && i(0) < range.nelem ())
+		retval = range.elem (i(0));
+	      else
+		retval = range.index (i);
+	    }
+        }
+      catch (idx_except& e)
+        {
+          e.set_pos_if_unset (1, 1);
+          throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
         }
 
       return retval;
diff --git a/libinterp/octave-value/ov-re-diag.cc b/libinterp/octave-value/ov-re-diag.cc
index 5c7cd2f..3a3aee5 100644
--- a/libinterp/octave-value/ov-re-diag.cc
+++ b/libinterp/octave-value/ov-re-diag.cc
@@ -92,31 +92,41 @@ octave_diag_matrix::do_index_op (const octave_value_list& idx,
   // vectors.
   if (! resize_ok && idx.length () == 2 && matrix.is_multiple_of_identity (1))
     {
-      idx_vector idx0 = idx(0).index_vector ();
-      idx_vector idx1 = idx(1).index_vector ();
-
-      if (! error_state)
+      int k = 0;        // index we're accesing when index_vector throws
+      try
         {
-          bool left = idx0.is_permutation (matrix.rows ());
-          bool right = idx1.is_permutation (matrix.cols ());
+          idx_vector idx0 = idx(0).index_vector ();
+          k = 1;
+          idx_vector idx1 = idx(1).index_vector ();
 
-          if (left && right)
+          if (! error_state)
             {
-              if (idx0.is_colon ()) left = false;
-              if (idx1.is_colon ()) right = false;
+              bool left = idx0.is_permutation (matrix.rows ());
+              bool right = idx1.is_permutation (matrix.cols ());
+
               if (left && right)
-                retval = PermMatrix (idx0, false) * PermMatrix (idx1, true);
-              else if (left)
-                retval = PermMatrix (idx0, false);
-              else if (right)
-                retval = PermMatrix (idx1, true);
-              else
                 {
-                  retval = this;
-                  this->count++;
+                  if (idx0.is_colon ()) left = false;
+                  if (idx1.is_colon ()) right = false;
+                  if (left && right)
+                    retval = PermMatrix (idx0, false) * PermMatrix (idx1, true);
+                  else if (left)
+                    retval = PermMatrix (idx0, false);
+                  else if (right)
+                    retval = PermMatrix (idx1, true);
+                  else
+                    {
+                      retval = this;
+                      this->count++;
+                    }
                 }
             }
         }
+      catch (idx_except& e)
+        {
+          e.set_pos_if_unset (2, k+1);
+          throw;   // caught in pt-idx.cc / pt-assign.cc to get var name
+        }
     }
 
   // if error_state is set, we've already griped.
diff --git a/libinterp/octave-value/ov-re-sparse.cc b/libinterp/octave-value/ov-re-sparse.cc
index aba5796..46e4356 100644
--- a/libinterp/octave-value/ov-re-sparse.cc
+++ b/libinterp/octave-value/ov-re-sparse.cc
@@ -61,8 +61,8 @@ octave_sparse_matrix::index_vector (bool /* require_integers */) const
     return idx_vector (array_value ());
   else
     {
-      std::string nm = type_name ();
-      error ("%s type invalid as index value", nm.c_str ());
+      std::string nm = "<" + type_name () + ">";
+      gripe_invalid_index (nm.c_str ());
       return idx_vector ();
     }
 }
diff --git a/libinterp/octave-value/ov-str-mat.cc b/libinterp/octave-value/ov-str-mat.cc
index 35d7e25..ea8f467 100644
--- a/libinterp/octave-value/ov-str-mat.cc
+++ b/libinterp/octave-value/ov-str-mat.cc
@@ -94,46 +94,60 @@ octave_char_matrix_str::do_index_op_internal (const octave_value_list& idx,
 
   octave_idx_type len = idx.length ();
 
-  switch (len)
+    // If we catch an indexing error in  index_vector(),  we flag an error in
+    // index  k.  Ensure it is the right value befor each idx_vector() call.
+    // Same variable as used in for() loop in default: case.
+  octave_idx_type k = 0;
+
+  try
+    {
+      switch (len)
+        {
+        case 0:
+          retval = octave_value (matrix, type);
+          break;
+
+        case 1:
+          {
+            idx_vector i = idx (0).index_vector ();
+
+            if (! error_state)
+              retval = octave_value (charNDArray (matrix.index (i, resize_ok)),
+                                     type);
+          }
+          break;
+
+        case 2:
+          {
+            idx_vector i = idx (0).index_vector ();
+            k = 1;
+            idx_vector j = idx (1).index_vector ();
+
+            if (! error_state)
+              retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)),
+                                     type);
+          }
+          break;
+
+        default:
+          {
+            Array<idx_vector> idx_vec (dim_vector (len, 1));
+
+            for (k = 0; k < len; k++)
+              idx_vec(k) = idx(k).index_vector ();
+
+            if (! error_state)
+              retval =
+                octave_value (charNDArray (matrix.index (idx_vec, resize_ok)),
+                              type);
+          }
+          break;
+        }
+    }
+  catch (idx_except& e)
     {
-    case 0:
-      retval = octave_value (matrix, type);
-      break;
-
-    case 1:
-      {
-        idx_vector i = idx (0).index_vector ();
-
-        if (! error_state)
-          retval = octave_value (charNDArray (matrix.index (i, resize_ok)),
-                                 type);
-      }
-      break;
-
-    case 2:
-      {
-        idx_vector i = idx (0).index_vector ();
-        idx_vector j = idx (1).index_vector ();
-
-        if (! error_state)
-          retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)),
-                                 type);
-      }
-      break;
-
-    default:
-      {
-        Array<idx_vector> idx_vec (dim_vector (len, 1));
-
-        for (octave_idx_type i = 0; i < len; i++)
-          idx_vec(i) = idx(i).index_vector ();
-
-        if (! error_state)
-          retval =
-            octave_value (charNDArray (matrix.index (idx_vec, resize_ok)),
-                          type);
-      }
-      break;
+      e.set_pos_if_unset (len, k+1);
+      throw;   // caught in pt-idx.cc / pt-assign.cc, when var name known
     }
 
   return retval;
diff --git a/libinterp/octave-value/ov.cc b/libinterp/octave-value/ov.cc
index 69371fd..c12aae4 100644
--- a/libinterp/octave-value/ov.cc
+++ b/libinterp/octave-value/ov.cc
@@ -1496,6 +1496,11 @@ octave_value::assign (assign_op op, const octave_value& rhs)
               // Usually unnecessary, but may be needed (complex arrays).
               maybe_mutate ();
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, assign");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -1997,6 +2002,11 @@ do_binary_op (octave_value::binary_op op,
             {
               retval = f (v1, v2);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, do_binary_op 1");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -2020,6 +2030,11 @@ do_binary_op (octave_value::binary_op op,
             {
               retval = f (*v1.rep, *v2.rep);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, do_binary_op 2");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -2148,6 +2163,12 @@ do_binary_op (octave_value::binary_op op,
                         {
                           retval = f (*tv1.rep, *tv2.rep);
                         }
+		      catch (idx_except& e)
+			{
+			  warning("internal error(?): unhandled index exception caught in ov, do_binary_op 3");
+                          (*current_liboctave_error_with_id_handler)
+                                                        (e.id(), e.err());
+			}
                       catch (octave_execution_exception)
                         {
                           gripe_library_execution_error ();
@@ -2256,6 +2277,11 @@ do_binary_op (octave_value::compound_binary_op op,
             {
               retval = f (v1, v2);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, do_binary_op 4");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -2275,6 +2301,11 @@ do_binary_op (octave_value::compound_binary_op op,
             {
               retval = f (*v1.rep, *v2.rep);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, do_binary_op 5");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -2321,6 +2352,11 @@ do_cat_op (const octave_value& v1, const octave_value& v2,
         {
           retval = f (*v1.rep, *v2.rep, ra_idx);
         }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, do_cat_op");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
       catch (octave_execution_exception)
         {
           gripe_library_execution_error ();
@@ -2526,6 +2562,11 @@ do_unary_op (octave_value::unary_op op, const octave_value& v)
             {
               retval = f (v);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, do_unary_op 1");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -2549,6 +2590,11 @@ do_unary_op (octave_value::unary_op op, const octave_value& v)
             {
               retval = f (*v.rep);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, do_unary_op 2");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -2619,6 +2665,11 @@ octave_value::do_non_const_unary_op (unary_op op)
             {
               f (*rep);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, non_const_unary_op 1");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
@@ -2647,6 +2698,11 @@ octave_value::do_non_const_unary_op (unary_op op)
                         {
                           f (*rep);
                         }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, non_const_unary_op 2");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
                       catch (octave_execution_exception)
                         {
                           gripe_library_execution_error ();
@@ -2695,6 +2751,11 @@ octave_value::do_non_const_unary_op (unary_op op)
             {
               f (*rep);
             }
+	  catch (idx_except& e)
+	    {
+	      warning("internal error(?): unhandled index exception caught in ov, non_const_unary_op 3");
+              (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+	    }
           catch (octave_execution_exception)
             {
               gripe_library_execution_error ();
diff --git a/libinterp/parse-tree/pt-assign.cc b/libinterp/parse-tree/pt-assign.cc
index a259001..42533f9 100644
--- a/libinterp/parse-tree/pt-assign.cc
+++ b/libinterp/parse-tree/pt-assign.cc
@@ -106,41 +106,49 @@ tree_simple_assignment::rvalue1 (int)
                     }
                 }
 
-              octave_lvalue ult = lhs->lvalue ();
-
-              if (ult.numel () != 1)
-                gripe_nonbraced_cs_list_assignment ();
-
-              if (! error_state)
+              try
                 {
-                  ult.assign (etype, rhs_val);
+                  octave_lvalue ult = lhs->lvalue ();
+
+                  if (ult.numel () != 1)
+                    gripe_nonbraced_cs_list_assignment ();
 
                   if (! error_state)
                     {
-                      if (etype == octave_value::op_asn_eq)
-                        retval = rhs_val;
-                      else
-                        retval = ult.value ();
+                      ult.assign (etype, rhs_val);
 
-                      if (print_result ()
-                          && tree_evaluator::statement_printing_enabled ())
+                      if (! error_state)
                         {
-                          // We clear any index here so that we can
-                          // get the new value of the referenced
-                          // object below, instead of the indexed
-                          // value (which should be the same as the
-                          // right hand side value).
-
-                          ult.clear_index ();
-
-                          octave_value lhs_val = ult.value ();
-
-                          if (! error_state)
-                            lhs_val.print_with_name (octave_stdout,
-                                                     lhs->name ());
+                          if (etype == octave_value::op_asn_eq)
+                            retval = rhs_val;
+                          else
+                            retval = ult.value ();
+
+                          if (print_result ()
+                              && tree_evaluator::statement_printing_enabled ())
+                            {
+                              // We clear any index here so that we can
+                              // get the new value of the referenced
+                              // object below, instead of the indexed
+                              // value (which should be the same as the
+                              // right hand side value).
+
+                              ult.clear_index ();
+
+                              octave_value lhs_val = ult.value ();
+
+                              if (! error_state)
+                                lhs_val.print_with_name (octave_stdout,
+                                                         lhs->name ());
+                            }
                         }
                     }
                 }
+              catch (idx_except& e)
+                {	// problems with range, invalid index type etc.
+                  e.set_var (lhs->name ());
+                  (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+                }
             }
         }
     }
diff --git a/libinterp/parse-tree/pt-eval.cc b/libinterp/parse-tree/pt-eval.cc
index 61846aa..5a16202 100644
--- a/libinterp/parse-tree/pt-eval.cc
+++ b/libinterp/parse-tree/pt-eval.cc
@@ -751,6 +751,12 @@ tree_evaluator::visit_statement (tree_statement& stmt)
               //                result_values(0) = tmp_result;
             }
         }
+      catch (idx_except& e)	// temporary code.  Remove when confident
+        {			// all exceptions are caught.
+				// (Will fall through to next case anyway.)
+	  warning("error: unhandled index exception in pt-eval");
+	  (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+        }
       catch (octave_execution_exception)
         {
           gripe_library_execution_error ();
diff --git a/libinterp/parse-tree/pt-id.h b/libinterp/parse-tree/pt-id.h
index 20eb997..c173262 100644
--- a/libinterp/parse-tree/pt-id.h
+++ b/libinterp/parse-tree/pt-id.h
@@ -66,7 +66,7 @@ public:
 
   bool is_defined (void) { return sym->is_defined (); }
 
-  virtual bool is_variable (void) { return sym->is_variable (); }
+  virtual bool is_variable (void) const { return sym->is_variable (); }
 
   virtual bool is_black_hole (void) { return false; }
 
@@ -152,7 +152,7 @@ public:
 
   std::string name (void) const { return "~"; }
 
-  bool is_variable (void) { return false; }
+  bool is_variable (void) const { return false; }
 
   bool is_black_hole (void) { return true; }
 
diff --git a/libinterp/parse-tree/pt-idx.cc b/libinterp/parse-tree/pt-idx.cc
index 212e276..e04bdac 100644
--- a/libinterp/parse-tree/pt-idx.cc
+++ b/libinterp/parse-tree/pt-idx.cc
@@ -284,6 +284,18 @@ tree_index_expression::rvalue (int nargout)
   return tree_index_expression::rvalue (nargout, 0);
 }
 
+// Final step of processing an indexing error.  Add the name of the
+// variable being indexed, if any, then issue an error.
+//    (Will this also be needed by  pt-lvalue,  which calls subsref?)
+void
+final_index_error (idx_except& e, const tree_expression *expr)
+{
+  if (expr->is_identifier () &&
+            dynamic_cast<const tree_identifier *> (expr)->is_variable ())
+    e.set_var (expr->name ());
+  (*current_liboctave_error_with_id_handler) (e.id (), e.err ());
+}
+
 octave_value_list
 tree_index_expression::rvalue (int nargout,
                                const std::list<octave_lvalue> *lvalue_list)
@@ -353,7 +365,7 @@ tree_index_expression::rvalue (int nargout,
 
               if (force_split || (al && al->has_magic_end ()))
                 {
-                  // We have an expression like
+                  // (we have force_split, or) we have an expression like
                   //
                   //   x{end}.a(end)
                   //
@@ -363,38 +375,45 @@ tree_index_expression::rvalue (int nargout,
                   // that argument list so we can pass the appropriate
                   // value to the built-in end function.
 
-                  octave_value_list tmp_list
-                    = tmp.subsref (type.substr (tmpi, i - tmpi), idx, nargout);
-
-                  tmp = tmp_list.length () ? tmp_list(0) : octave_value ();
-                  tmpi = i;
-                  idx.clear ();
+                  try
+                    {
+                      octave_value_list tmp_list
+                        =tmp.subsref (type.substr (tmpi, i-tmpi), idx, nargout);
 
-                  if (tmp.is_cs_list ())
-                    gripe_indexed_cs_list ();
+                      tmp = tmp_list.length () ? tmp_list(0) : octave_value ();
+                      tmpi = i;
+                      idx.clear ();
 
-                  if (error_state)
-                    break;
+                      if (tmp.is_cs_list ())
+                        gripe_indexed_cs_list ();
 
-                  if (tmp.is_function ())
-                    {
-                      octave_function *fcn = tmp.function_value (true);
+                      if (error_state)
+                        break;
 
-                      if (fcn && ! fcn->is_postfix_index_handled (type[i]))
+                      if (tmp.is_function ())
                         {
-                          octave_value_list empty_args;
+                          octave_function *fcn = tmp.function_value (true);
 
-                          tmp_list = tmp.do_multi_index_op (1, empty_args);
-                          tmp = (tmp_list.length ()
-                                 ? tmp_list(0) : octave_value ());
+                          if (fcn && ! fcn->is_postfix_index_handled (type[i]))
+                            {
+                              octave_value_list empty_args;
 
-                          if (tmp.is_cs_list ())
-                            gripe_indexed_cs_list ();
+                              tmp_list = tmp.do_multi_index_op (1, empty_args);
+                              tmp = (tmp_list.length ()
+                                     ? tmp_list(0) : octave_value ());
 
-                          if (error_state)
-                            break;
+                              if (tmp.is_cs_list ())
+                                gripe_indexed_cs_list ();
+
+                              if (error_state)
+                                break;
+                            }
                         }
                     }
+                  catch (idx_except& e)  // problems with index range, type etc.
+                    {
+                      final_index_error (e, expr);
+                    }
                 }
             }
 
@@ -433,8 +452,15 @@ tree_index_expression::rvalue (int nargout,
 
       if (! error_state)
         {
-          retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
-                                lvalue_list);
+	  try
+	    {
+	      retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
+				    lvalue_list);
+	    }
+	  catch (idx_except& e)	// problems with range, invalid index type etc.
+	    {
+	      final_index_error (e, expr);
+	    }
 
           octave_value val = retval.length () ? retval(0) : octave_value ();
 
@@ -500,7 +526,14 @@ tree_index_expression::lvalue (void)
             gripe_indexed_cs_list ();
           else if (tmpi < i)
             {
-              tmp = tmp.subsref (type.substr (tmpi, i - tmpi), tmpidx, true);
+              try
+                {
+                  tmp = tmp.subsref (type.substr (tmpi, i-tmpi), tmpidx, true);
+                }
+              catch (idx_except& e)  // problems with range, invalid type etc.
+                {
+                  final_index_error (e, expr);
+                }
               tmpidx.clear ();
             }
 
diff --git a/liboctave/array/Array-util.cc b/liboctave/array/Array-util.cc
index 26ab018..2775d3a 100644
--- a/liboctave/array/Array-util.cc
+++ b/liboctave/array/Array-util.cc
@@ -178,9 +178,9 @@ octave_idx_type
 compute_index (octave_idx_type n, const dim_vector& dims)
 {
   if (n < 0)
-    gripe_invalid_index ();
+    gripe_invalid_index (n, 1, 1);
   if (n >= dims.numel ())
-    gripe_index_out_of_range (1, 1, n+1, dims.numel ());
+    gripe_index_out_of_range (1, 1, n+1, dims.numel (), dims);
 
   return n;
 }
@@ -188,12 +188,14 @@ compute_index (octave_idx_type n, const dim_vector& dims)
 octave_idx_type
 compute_index (octave_idx_type i, octave_idx_type j, const dim_vector& dims)
 {
-  if (i < 0 || j < 0)
-    gripe_invalid_index ();
+  if (i < 0)
+    gripe_invalid_index (i, 2, 1);
+  else if (j < 0)
+    gripe_invalid_index (j, 2, 2);
   if (i >= dims(0))
-    gripe_index_out_of_range (2, 1, i+1, dims(0));
+    gripe_index_out_of_range (2, 1, i+1, dims(0), dims);
   if (j >= dims.numel (1))
-    gripe_index_out_of_range (2, 2, j+1, dims.numel (1));
+    gripe_index_out_of_range (2, 2, j+1, dims.numel (1), dims);
 
   return j*dims(0) + i;
 }
@@ -202,14 +204,18 @@ octave_idx_type
 compute_index (octave_idx_type i, octave_idx_type j, octave_idx_type k,
                const dim_vector& dims)
 {
-  if (i < 0 || j < 0 || k < 0)
-    gripe_invalid_index ();
+  if (i < 0)
+    gripe_invalid_index (i, 3, 1);
+  else if (j < 0)
+    gripe_invalid_index (j, 3, 2);
+  else if (k < 0)
+    gripe_invalid_index (k, 3, 3);
   if (i >= dims(0))
-    gripe_index_out_of_range (3, 1, i+1, dims(0));
+    gripe_index_out_of_range (3, 1, i+1, dims(0), dims);
   if (j >= dims(1))
-    gripe_index_out_of_range (3, 2, j+1, dims(1));
+    gripe_index_out_of_range (3, 2, j+1, dims(1), dims);
   if (k >= dims.numel (2))
-    gripe_index_out_of_range (3, 3, k+1, dims.numel (2));
+    gripe_index_out_of_range (3, 3, k+1, dims.numel (2), dims);
 
   return (k*dims(1) + j)*dims(0) + i;
 }
@@ -222,9 +228,9 @@ compute_index (const Array<octave_idx_type>& ra_idx, const dim_vector& dims)
   for (int d = 0; d < nd; d++)
     {
       if (ra_idx(d) < 0)
-        gripe_invalid_index ();
+        gripe_invalid_index (ra_idx(d), nd, d+1);
       if (ra_idx(d) >= dv(d))
-        gripe_index_out_of_range (nd, d+1, ra_idx(d)+1, dv(d));
+        gripe_index_out_of_range (nd, d+1, ra_idx(d)+1, dv(d), dims);
     }
 
   return dv.compute_index (ra_idx.data ());
@@ -540,18 +546,29 @@ sub2ind (const dim_vector& dv, const Array<idx_vector>& idxa)
 
       for (octave_idx_type i = 0; i < len; i++)
         {
-          idx_vector idx = idxa(i);
-          octave_idx_type n = dvx(i);
+          try
+            {
+              idx_vector idx = idxa(i);
+              octave_idx_type n = dvx(i);
 
-          all_ranges = all_ranges && idx.is_range ();
-          if (clen < 0)
-            clen = idx.length (n);
-          else if (clen != idx.length (n))
-            current_liboctave_error_handler ("sub2ind: lengths of indices must match");
+              all_ranges = all_ranges && idx.is_range ();
+              if (clen < 0)
+                clen = idx.length (n);
+              else if (clen != idx.length (n))
+                current_liboctave_error_handler ("sub2ind: lengths of indices must match");
 
-          if (idx.extent (n) > n)
-            current_liboctave_error_handler ("sub2ind: index out of range");
+              if (idx.extent (n) > n)
+                  gripe_index_out_of_range (len, i+1, idx.extent (n), n);
+            }
+          catch (idx_except& e)
+            {
+	      e.set_pos_if_unset (len, i+1);
+	      e.set_var ("");		// no particular variable
+	      (*current_liboctave_error_with_id_handler) (e.id(), e.err());
+            }
         }
+      // idxa known to be valid. Shouldn't need to catch idx_except below here.
+
 
       if (len == 1)
         retval = idxa(0);
@@ -561,7 +578,7 @@ sub2ind (const dim_vector& dv, const Array<idx_vector>& idxa)
           octave_idx_type idx = idxa(len-1)(0);
           for (octave_idx_type i = len - 2; i >= 0; i--)
             idx = idx * dvx(i) + idxa(i)(0);
-          retval = idx_vector (idx);
+            retval = idx_vector (idx);
         }
       else if (all_ranges && clen != 0)
         {
@@ -575,7 +592,7 @@ sub2ind (const dim_vector& dv, const Array<idx_vector>& idxa)
               start = start * dvx(i) + xstart;
               step = step * dvx(i) + xstep;
             }
-          retval = idx_vector::make_range (start, step, clen);
+	  retval = idx_vector::make_range (start, step, clen);
         }
       else
         {
@@ -590,7 +607,7 @@ sub2ind (const dim_vector& dv, const Array<idx_vector>& idxa)
                 idxa(i).copy_data (idx_vec);
             }
 
-          retval = idx_vector (idx);
+	  retval = idx_vector (idx);
         }
     }
   else
diff --git a/liboctave/array/Array.cc b/liboctave/array/Array.cc
index 882ba59..d5713c1 100644
--- a/liboctave/array/Array.cc
+++ b/liboctave/array/Array.cc
@@ -190,9 +190,9 @@ Array<T>::checkelem (octave_idx_type n)
 {
   // Do checks directly to avoid recomputing slice_len.
   if (n < 0)
-    gripe_invalid_index ();
+    gripe_invalid_index (n);
   if (n >= slice_len)
-    gripe_index_out_of_range (1, 1, n+1, slice_len);
+    gripe_index_out_of_range (1, 1, n+1, slice_len, dimensions);
 
   return elem (n);
 }
@@ -224,9 +224,9 @@ Array<T>::checkelem (octave_idx_type n) const
 {
   // Do checks directly to avoid recomputing slice_len.
   if (n < 0)
-    gripe_invalid_index ();
+    gripe_invalid_index (n);
   if (n >= slice_len)
-    gripe_index_out_of_range (1, 1, n+1, slice_len);
+    gripe_index_out_of_range (1, 1, n+1, slice_len, dimensions);
 
   return elem (n);
 }
@@ -260,7 +260,7 @@ Array<T>::column (octave_idx_type k) const
   octave_idx_type r = dimensions(0);
 #ifdef BOUNDS_CHECKING
   if (k < 0 || k > dimensions.numel (1))
-    gripe_index_out_of_range (2, 2, k+1, dimensions.numel (1));
+    gripe_index_out_of_range (2, 2, k+1, dimensions.numel (1), dimensions);
 #endif
 
   return Array<T> (*this, dim_vector (r, 1), k*r, k*r + r);
@@ -275,7 +275,7 @@ Array<T>::page (octave_idx_type k) const
   octave_idx_type p = r*c;
 #ifdef BOUNDS_CHECKING
   if (k < 0 || k > dimensions.numel (2))
-    gripe_index_out_of_range (3, 3, k+1, dimensions.numel (2));
+    gripe_index_out_of_range (3, 3, k+1, dimensions.numel (2), dimensions);
 #endif
 
   return Array<T> (*this, dim_vector (r, c), k*p, k*p + p);
@@ -287,9 +287,9 @@ Array<T>::linear_slice (octave_idx_type lo, octave_idx_type up) const
 {
 #ifdef BOUNDS_CHECKING
   if (lo < 0)
-    gripe_index_out_of_range (1, 1, lo+1, numel ());
+    gripe_index_out_of_range (1, 1, lo+1, numel (), dimensions);
   if (up > numel ())
-    gripe_index_out_of_range (1, 1, up, numel ());
+    gripe_index_out_of_range (1, 1, up, numel (), dimensions);
 #endif
   if (up < lo) up = lo;
   return Array<T> (*this, dim_vector (up - lo, 1), lo, up);
@@ -726,7 +726,7 @@ Array<T>::index (const idx_vector& i) const
   else
     {
       if (i.extent (n) != n)
-        gripe_index_out_of_range (1, 1, i.extent (n), n); // throws
+        gripe_index_out_of_range (1, 1, i.extent (n), n, dimensions); // throws
 
       // FIXME: this is the only place where orig_dimensions are used.
       dim_vector rd = i.orig_dimensions ();
@@ -793,9 +793,9 @@ Array<T>::index (const idx_vector& i, const idx_vector& j) const
   else
     {
       if (i.extent (r) != r)
-        gripe_index_out_of_range (2, 1, i.extent (r), r); // throws
+        gripe_index_out_of_range (2, 1, i.extent (r), r, dimensions); // throws
       if (j.extent (c) != c)
-        gripe_index_out_of_range (2, 2, j.extent (c), c); // throws
+        gripe_index_out_of_range (2, 2, j.extent (c), c, dimensions); // throws
 
       octave_idx_type n = numel ();
       octave_idx_type il = i.length (r);
@@ -855,7 +855,7 @@ Array<T>::index (const Array<idx_vector>& ia) const
       for (int i = 0; i < ial; i++)
         {
           if (ia(i).extent (dv(i)) != dv(i))
-            gripe_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i)); // throws
+            gripe_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i), dimensions); // throws
 
           all_colons = all_colons && ia(i).is_colon ();
         }
@@ -1180,7 +1180,7 @@ Array<T>::assign (const idx_vector& i, const Array<T>& rhs, const T& rfv)
         }
     }
   else
-    gripe_invalid_assignment_size ();
+    gripe_nonconformant ("=", dim_vector(i.length(n),1), rhs.dims());
 }
 
 template <class T>
@@ -1282,7 +1282,7 @@ Array<T>::assign (const idx_vector& i, const idx_vector& j,
         }
     }
   else
-    gripe_assignment_dimension_mismatch ();
+    gripe_nonconformant ("=", il, jl, rhs.dim1(), rhs.dim2());
 }
 
 template <class T>
@@ -1384,10 +1384,18 @@ Array<T>::assign (const Array<idx_vector>& ia,
             }
         }
       else
-        gripe_assignment_dimension_mismatch ();
+	gripe_nonconformant  ("=", dv, rhdv);
     }
 }
 
+/*
+%!shared a
+%! a = [1 2; 3 4];
+%!error <op1 is 1x2, op2 is 1x3> a(1,:) = [1 2 3]
+%!error <op1 is 2x1, op2 is 1x3> a(:,1) = [1 2 3]
+%!error <op1 is 2x2, op2 is 2x1> a(1:2,2:3) = [1;2]
+*/
+
 template <class T>
 void
 Array<T>::delete_elements (const idx_vector& i)
diff --git a/liboctave/array/DiagArray2.cc b/liboctave/array/DiagArray2.cc
index 78c794a..eb404ba 100644
--- a/liboctave/array/DiagArray2.cc
+++ b/liboctave/array/DiagArray2.cc
@@ -126,13 +126,13 @@ DiagArray2<T>::check_idx (octave_idx_type r, octave_idx_type c) const
 
   if (r < 0 || r >= dim1 ())
     {
-      gripe_index_out_of_range (2, 1, r+1, dim1 ());
+      gripe_index_out_of_range (2, 1, r+1, dim1 (), dims ());
       ok = false;
     }
 
   if (c < 0 || c >= dim2 ())
     {
-      gripe_index_out_of_range (2, 2, c+1, dim2 ());
+      gripe_index_out_of_range (2, 2, c+1, dim2 (), dims ());
       ok = false;
     }
 
diff --git a/liboctave/array/Sparse.cc b/liboctave/array/Sparse.cc
index c861d3e..ea93ce7 100644
--- a/liboctave/array/Sparse.cc
+++ b/liboctave/array/Sparse.cc
@@ -1431,7 +1431,7 @@ Sparse<T>::index (const idx_vector& idx, bool resize_ok) const
           retval = tmp.index (idx);
         }
       else
-        gripe_index_out_of_range (1, 1, idx.extent (nel), nel);
+        gripe_index_out_of_range (1, 1, idx.extent (nel), nel, dims ());
     }
   else if (nr == 1 && nc == 1)
     {
@@ -1614,9 +1614,9 @@ Sparse<T>::index (const idx_vector& idx_i, const idx_vector& idx_j,
           retval = tmp.index (idx_i, idx_j);
         }
       else if (idx_i.extent (nr) > nr)
-        gripe_index_out_of_range (2, 1, idx_i.extent (nr), nr);
+        gripe_index_out_of_range (2, 1, idx_i.extent (nr), nr, dims ());
       else
-        gripe_index_out_of_range (2, 2, idx_j.extent (nc), nc);
+        gripe_index_out_of_range (2, 2, idx_j.extent (nc), nc, dims ());
     }
   else if (nr == 1 && nc == 1)
     {
@@ -1978,7 +1978,7 @@ Sparse<T>::assign (const idx_vector& idx, const Sparse<T>& rhs)
         assign (idx, Sparse<T> (rhl, 1));
     }
   else
-    gripe_invalid_assignment_size ();
+    gripe_nonconformant ("=", dim_vector(idx.length (n),1), rhs.dims());
 }
 
 template <class T>
@@ -2214,7 +2214,7 @@ Sparse<T>::assign (const idx_vector& idx_i,
         assign (idx_i, idx_j, Sparse<T> (n, m));
     }
   else
-    gripe_assignment_dimension_mismatch ();
+    gripe_nonconformant  ("=", idx_i.length (nr), idx_j.length (nc), n, m);
 }
 
 // Can't use versions of these in Array.cc due to duplication of the
diff --git a/liboctave/array/idx-vector.cc b/liboctave/array/idx-vector.cc
index a5fc261..2d4e70e 100644
--- a/liboctave/array/idx-vector.cc
+++ b/liboctave/array/idx-vector.cc
@@ -113,9 +113,14 @@ idx_vector::idx_range_rep::idx_range_rep (octave_idx_type _start,
       gripe_invalid_range ();
       err = true;
     }
-  else if (start < 0 || (step < 0 && start + (len-1)*step < 0))
+  else if (start < 0)
     {
-      gripe_invalid_index ();
+      gripe_invalid_index (start);
+      err = true;
+    }
+  else if (step < 0 && start + (len-1)*step < 0)
+    {
+      gripe_invalid_index (start + (len-1)*step);
       err = true;
     }
 }
@@ -134,15 +139,23 @@ idx_vector::idx_range_rep::idx_range_rep (const Range& r)
         {
           start = static_cast<octave_idx_type> (r.base ()) - 1;
           step = static_cast<octave_idx_type> (r.inc ());
-          if (start < 0 || (step < 0 && start + (len-1)*step < 0))
+          if (start < 0)
+            {
+              gripe_invalid_index (start);
+              err = true;
+            }
+          else if (step < 0 && start + (len-1)*step < 0)
             {
-              gripe_invalid_index ();
+              gripe_invalid_index (start + (len-1)*step);
               err = true;
             }
         }
       else
         {
-          gripe_invalid_index ();
+	  // find first non-integer, then gripe about it
+	  double b = r.base();
+	  double inc = r.inc();
+          gripe_invalid_index (b != floor(b) ? b : b+inc);
           err = true;
         }
     }
@@ -221,7 +234,11 @@ convert_index (octave_idx_type i, bool& conv_error,
                octave_idx_type& ext)
 {
   if (i <= 0)
-    conv_error = true;
+    {
+      if (!conv_error)		// only gripe once, for things like A(-10000:0)
+        gripe_invalid_index (i-1);
+      conv_error = true;
+    }
 
   if (ext < i)
     ext = i;
@@ -235,7 +252,10 @@ convert_index (double x, bool& conv_error, octave_idx_type& ext)
   octave_idx_type i = static_cast<octave_idx_type> (x);
 
   if (static_cast<double> (i) != x)
-    conv_error = true;
+    {
+      gripe_invalid_index (x-1);
+      conv_error = true;
+    }
 
   return convert_index (i, conv_error, ext);
 }
@@ -264,9 +284,6 @@ idx_vector::idx_scalar_rep::idx_scalar_rep (T x)
   octave_idx_type dummy = 0;
 
   data = convert_index (x, err, dummy);
-
-  if (err)
-    gripe_invalid_index ();
 }
 
 idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i)
@@ -274,7 +291,7 @@ idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i)
 {
   if (data < 0)
     {
-      gripe_invalid_index ();
+      gripe_invalid_index (data);
       err = true;
     }
 }
@@ -327,10 +344,7 @@ idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>& nda)
       data = d;
 
       if (err)
-        {
-          delete [] data;
-          gripe_invalid_index ();
-        }
+        delete [] data;
     }
 }
 
@@ -347,15 +361,16 @@ idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda)
         {
           octave_idx_type k = inda.xelem (i);
           if (k < 0)
-            err = true;
+	    {
+	      if (!err)		// only report first error, in case 1000s.
+		gripe_invalid_index (k);
+              err = true;
+	    }
           else if (k > max)
             max = k;
         }
 
       ext = max + 1;
-
-      if (err)
-        gripe_invalid_index ();
     }
 }
 
@@ -459,7 +474,7 @@ idx_vector::idx_vector_rep::checkelem (octave_idx_type n) const
 {
   if (n < 0 || n >= len)
     {
-      gripe_invalid_index ();
+      gripe_invalid_index (n);
       return 0;
     }
 
@@ -709,7 +724,7 @@ idx_vector::idx_mask_rep::checkelem (octave_idx_type n) const
 {
   if (n < 0 || n >= len)
     {
-      gripe_invalid_index ();
+      gripe_invalid_index (n);
       return 0;
     }
 
diff --git a/liboctave/util/lo-array-gripes.cc b/liboctave/util/lo-array-gripes.cc
index 7e476bc..5219f3e 100644
--- a/liboctave/util/lo-array-gripes.cc
+++ b/liboctave/util/lo-array-gripes.cc
@@ -25,6 +25,7 @@ along with Octave; see the file COPYING.  If not, see
 #include <config.h>
 #endif
 
+#include <string.h>
 #include "lo-array-gripes.h"
 #include "lo-error.h"
 
@@ -90,34 +91,6 @@ gripe_nonconformant (const char *op, const dim_vector& op1_dims,
 }
 
 void
-gripe_index_out_of_range (int nd, int dim, octave_idx_type idx,
-                          octave_idx_type ext)
-{
-  const char *err_id = error_id_index_out_of_bounds;
-
-  switch (nd)
-    {
-    case 1:
-      (*current_liboctave_error_with_id_handler)
-        (err_id, "A(I): index out of bounds; value %d out of bound %d",
-         idx, ext);
-      break;
-
-    case 2:
-      (*current_liboctave_error_with_id_handler)
-        (err_id, "A(I,J): %s index out of bounds; value %d out of bound %d",
-         (dim == 1) ? "row" : "column", idx, ext);
-      break;
-
-    default:
-      (*current_liboctave_error_with_id_handler)
-        (err_id, "A(I,J,...): index to dimension %d out of bounds; value %d out of bound %d",
-         dim, idx, ext);
-      break;
-    }
-}
-
-void
 gripe_del_index_out_of_range (bool is1d, octave_idx_type idx,
                               octave_idx_type ext)
 {
@@ -128,19 +101,201 @@ gripe_del_index_out_of_range (bool is1d, octave_idx_type idx,
      is1d ? "I" : "..,I,..", idx, ext);
 }
 
-void
-gripe_invalid_index (void)
+
+
+/******************************************************************************/
+/* Common procedures of base class idx_except, thrown whenever an object is */
+/* indexed incorrectly, such as by an index that is out of range, negative, */
+/* fractional, complex, or of a non-numeric type. */
+const char*
+idx_except::err() throw()
 {
-  const char *err_id = error_id_invalid_index;
+    msg = (access()+"; "+explain());
+    return msg.c_str();
+}
 
-  (*current_liboctave_error_with_id_handler)
+// Show what was illegally accessed, e.g.,  "A(-1,_)", "A(0+1i)", "A(_,3)"
+// Show how many indices come before/after the offending one,
+// e.g., (<error>), (<error>,_), or (_,<error>,...[x5]...)
+std::string
+idx_except:: access() const
+{
+  int buf_len = 300;
+  char output [buf_len], pre [buf_len], post [buf_len];
+
+           // dim == 0 if position not yet given, or
+           // <static_cast unsigned int>(-1) if explicitly shown to be unknown
+           // both are caught by this condition
+  if (static_cast <unsigned int> (dim-1) > 100000)
+    {      // No parentheses are given if the dimension is not known.
+      pre[0] = post[0] = '\0';
+    }
+  else
+    {
+      if (dim < 5)
+        {
+          pre[0] = '(';
+          octave_idx_type i;
+          for (i = 1; i < dim; i++)
+            {
+              pre[2*i-1] = '_';
+              pre[2*i]   = ',';
+            }
+          pre[2*i-1] = '\0';    // i == min (1, dim)
+        }
+      else
+        {
+          sprintf (pre, "(...[x%d]...", dim-1);
+        }
+
+      if (static_cast <unsigned int> (nd-dim) < 5)
+        {
+          for (octave_idx_type i = 0; i < nd-dim; i++)
+            {
+              post[2*i]   = ',';
+              post[2*i+1] = '_';
+            }
+          if (nd >= dim)
+            {
+              post[2*(nd-dim)] = ')';
+              post[2*(nd-dim)+1] = '\0';
+            }
+        }
+      else
+        {
+          sprintf (post, "...[x%d]...)", nd-dim);
+        }
+    }
+  const char *v;
+  if (var[0] == '\0' || var == "<unknown>")
+    v = "index ";
+  else
+    v = var.c_str ();
+
+  snprintf (output, buf_len, "%s%s%s%s", v, pre, idx(), post);
+  return (output);
+}
+
+/******************************************************************************/
+class invalid_index : public idx_except
+{
+  virtual const char* explain() const
+  {
+    return ("subscripts must be either integers 1..."
 #ifdef USE_64_BIT_IDX_T
-    (err_id, "subscript indices must be either positive integers less than 2^63 or logicals");
+        "(2^63)-1"
 #else
-    (err_id, "subscript indices must be either positive integers less than 2^31 or logicals");
+        "(2^31)-1"
 #endif
+        " or logicals");
+  }
+  virtual const char* id() const        // ID of error to throw
+  { return (error_id_invalid_index); }
+
+  public:
+  invalid_index (const char *value, octave_idx_type nd, octave_idx_type dim)
+        : idx_except (value, nd, dim)
+    { }
+};
+
+// Complain of an index that is: negative, fractional, or too big
+void
+gripe_invalid_index (const char *idx, octave_idx_type nd, octave_idx_type dim, const char * /* var */)
+{
+    invalid_index e(idx, nd, dim);
+    throw e;
+}
+
+void
+gripe_invalid_index (octave_idx_type n, octave_idx_type nd, octave_idx_type dim, const char *var)
+{
+  char buf [100];
+  sprintf (buf, "%d", n+1);
+  gripe_invalid_index (buf, nd, dim, var);
 }
 
+void
+gripe_invalid_index (double n, octave_idx_type nd, octave_idx_type dim, const char *var)
+{
+  char buf [100];
+  sprintf (buf, "%g", n+1);
+  gripe_invalid_index (buf, nd, dim, var);
+}
+
+
+/******************************************************************************/
+/* gripe and exception for read access beyond the bounds of an array */
+class out_of_range : public idx_except
+{
+  dim_vector  size;         // dimension of object being accessed
+  octave_idx_type extent;   // length of dimension being accessed
+
+  virtual const char* explain() const
+  {
+    static std::string expl;    // should probably be member variable, but
+                                // then explain() can't be const.
+
+    if (nd >= size.length ())   // if not an index slice
+      {
+        if (var != "")
+          expl = "but " + var + " has size ";
+        else
+          expl = "but object has size ";
+        expl = expl + size.str ('x');
+      }
+    else
+      {
+        char buf [100];
+        sprintf (buf, "%d", extent);
+        expl = "out of bound " + std::string (buf);
+      }
+
+    return expl.c_str ();
+  }
+  virtual const char* id() const        // ID of error to throw
+  { return (error_id_index_out_of_bounds); }
+
+  public:
+  out_of_range (const char *value, octave_idx_type nd_in,octave_idx_type dim_in)
+        : idx_except (value, nd_in, dim_in), extent(0)
+    { }
+
+  void set_size (const dim_vector& size_in) { size = size_in; }
+  void set_extent (octave_idx_type ext)     { extent = ext; }
+};
+
+// Complain of an index that is out of range, but we don't know matrix size
+void
+gripe_index_out_of_range (int nd, int dim, octave_idx_type idx,
+                          octave_idx_type ext)
+{
+    char buf [100];
+    sprintf (buf, "%d", idx);
+    out_of_range e (buf, nd, dim);
+
+    e.set_extent (ext);
+    dim_vector d (1,1,1,1,1,1,1);   // make  explain()  give extent not size
+    e.set_size (d);
+    throw e;
+}
+
+// Complain of an index that is out of range
+void
+gripe_index_out_of_range (int nd, int dim, octave_idx_type idx,
+                          octave_idx_type ext, const dim_vector& d)
+{
+    char buf [100];
+    sprintf (buf, "%d", idx);
+    out_of_range e (buf, nd, dim);
+
+    e.set_extent (ext);
+    e.set_size (d);
+    throw e;
+}
+
+
+/******************************************************************************/
+
 // FIXME: the following is a common error message to resize,
 // regardless of whether it's called from assign or elsewhere.  It
 // seems OK to me, but eventually the gripe can be specialized.
@@ -157,20 +312,6 @@ gripe_invalid_resize (void)
 }
 
 void
-gripe_invalid_assignment_size (void)
-{
-  (*current_liboctave_error_handler)
-    ("A(I) = X: X must have the same size as I");
-}
-
-void
-gripe_assignment_dimension_mismatch (void)
-{
-  (*current_liboctave_error_handler)
-    ("A(I,J,...) = X: dimensions mismatch");
-}
-
-void
 gripe_singular_matrix (double rcond)
 {
   if (rcond == 0.0)
@@ -186,3 +327,5 @@ gripe_singular_matrix (double rcond)
          "matrix singular to machine precision, rcond = %g", rcond);
     }
 }
+
+/* Tests in test/index.tst */
diff --git a/liboctave/util/lo-array-gripes.h b/liboctave/util/lo-array-gripes.h
index 6b9c85d..fc0d6a8 100644
--- a/liboctave/util/lo-array-gripes.h
+++ b/liboctave/util/lo-array-gripes.h
@@ -24,6 +24,55 @@ along with Octave; see the file COPYING.  If not, see
 #define octave_lo_array_gripes_h 1
 
 #include "dim-vector.h"
+#include "quit.h"
+
+// Exception thrown by gripe_invalid_index
+// This is thrown when the invalid index is detected, at which point nd and dim
+// are usually not known.  It is caught at the place they are known, where a
+// new  gripe_invalid_index  is called.
+//
+// Typically, this should be caught after any call to
+// octave_value_list::index_vector()
+class idx_except : public octave_execution_exception
+{
+  std::string index;    // value of invalid index
+  std::string msg;	// formatted message returned by what(), (not on stack)
+
+  protected:
+  std::string access() const;	// Show what's wrong, e.g.,  A(-1,_), A(0+1i)
+  octave_idx_type nd;   // number of dimensions of indexed object
+  octave_idx_type dim;  // dimension number in which invalid index occurred
+
+  std::string var;      // Name of variable being indexed
+
+  public:
+    // erroneous index value.  Called in what(), and by external code
+    // (e.g., nth_element) to make a custom error message
+  const char* idx() const { return index.c_str (); }
+  virtual const char* explain() const = 0;   // details set by subclass
+
+  virtual const char* id() const = 0;        // ID of error to throw
+  virtual const char* err () throw();
+  idx_except (const char *index_in, octave_idx_type nd_in=0, octave_idx_type dim_in=0, const char *var_in="") :
+      index(index_in), nd(nd_in), dim(dim_in), var(var_in)
+    { }
+  ~idx_except() throw() {}
+
+        // "position" of error: dimension in error, and number of dimensions
+  void set_pos (octave_idx_type nd_in, octave_idx_type dim_in)
+    { nd = nd_in; dim = dim_in; }
+  void set_pos_if_unset (octave_idx_type nd_in, octave_idx_type dim_in)
+    {
+      if (nd == 0)
+        {
+          nd  = nd_in;
+          dim = dim_in;
+        }
+    }
+        // name of variable being indexed.  eye(2)(1,1) gives "<unknown>"
+  void set_var (std::string var_in)
+    { var = var_in; }
+};
 
 extern OCTAVE_API const char *error_id_nonconformant_args;
 
@@ -57,6 +106,11 @@ gripe_nonconformant (const char *op, const dim_vector& op1_dims,
 
 extern void OCTAVE_API
 gripe_index_out_of_range (int nd, int dim,
+                          octave_idx_type iext, octave_idx_type ext,
+                          const dim_vector& d);
+
+extern void OCTAVE_API
+gripe_index_out_of_range (int nd, int dim,
                           octave_idx_type iext, octave_idx_type ext);
 
 extern void OCTAVE_API
@@ -64,16 +118,19 @@ gripe_del_index_out_of_range (bool is1d, octave_idx_type iext,
                               octave_idx_type ext);
 
 extern void OCTAVE_API
-gripe_invalid_index (void);
+gripe_invalid_index (double, octave_idx_type nd=0,
+                     octave_idx_type dim=0, const char *var = NULL);
 
 extern void OCTAVE_API
-gripe_invalid_resize (void);
+gripe_invalid_index (octave_idx_type n, octave_idx_type nd=0,
+                     octave_idx_type dim=0, const char *var = NULL);
 
 extern void OCTAVE_API
-gripe_invalid_assignment_size (void);
+gripe_invalid_index (const char *idx, octave_idx_type nd=0,
+                     octave_idx_type dim=0, const char *var = NULL);
 
 extern void OCTAVE_API
-gripe_assignment_dimension_mismatch (void);
+gripe_invalid_resize (void);
 
 extern void OCTAVE_API
 gripe_singular_matrix (double rcond = 0.0);
diff --git a/test/index.tst b/test/index.tst
index 6bc83f4..56b0fae 100644
--- a/test/index.tst
+++ b/test/index.tst
@@ -205,12 +205,6 @@
 
 %!error (a(1:2,1:2) = 1:4)
 
-%!shared x
-%! x = 1:5;
-%!error <attempted to use a complex scalar as an index> x(i)
-%!error <attempted to use a complex scalar as an index> x(j)
-%!error <attempted to use a complex scalar as an index> x(1+i)
-
 ## bug #38357
 %!shared d, dd
 %! d = diag ([1, 2, 3]);
@@ -501,3 +495,84 @@
 %! x = ones (2, 2);
 %! x([], false, :) = [];
 %! assert (x, y);
+
+
+  ##  Test indexing of unnamed constants
+%!error <index \(0\); subscripts must be>     1(0)
+%!error <index \(-1\); subscripts must be>    1(-1)
+%!error <index \(_,0.5\); subscripts>                 {}(1,0.5)
+%!error <index \(nan,_\); subscripts>                 1(NaN,1)
+%!error <index \(_,_,<cell....\[x8\]...\); subscripts> [](1,1,{},1,1,1,1,1,1,1,1)
+%!error <index \(...\[x9\]...-1,_\); subscript>      1(1,1,1,1,1,1,1,1,1,-1,1)
+%!error <index \(2\); out of bound 1>                1(2)
+%!error <index \(1\); out of bound 0>                [](1)
+%!error <index \(_,1\); but object has size 5x0>     zeros(5,0)(3,1)
+%!error <index \(3,_\); but object has size 0x5>     zeros(0,5)(3,1)
+%!error <index \(-1\); subscripts>                   1(1)(-1)(1)
+%!
+%!shared abc
+%! abc = [1, 2];
+%! ##  Test full matrices in variables
+%!error <abc\(3\); out of bound 2>      abc([false, true, true])
+%!error <abc\(-1\); subscripts>         abc(-1)(1)(1)
+%! ## xerror <index \(-1\); subscripts> abc(1)(-1)(1)   ## why no 'xerror' test?
+
+%!shared abc
+%! abc = [1 2; 3 4];
+%!error <abc\(5\); out of bound 4>         abc(5)
+%!error <abc\(_,3\); but abc has size 2x2> abc(2,3)
+%!error <abc\(_,_,0.5\); subscripts>       exp (abc(2,3,0.5))
+
+%!shared abc
+%! abc = [1 2; 3 4]; abc(1,1,2) = 1;
+%!error <abc\(_,5\); out of bound 4>                            abc(2,5)
+%!error <abc\(_,3,_\); but abc has size 2x2x2>                  abc(2,3,2)
+%!error <A\(..,I,..\) = \[\]: .* value 3 out of bound 2>        abc(3,:) = []
+%!error <A\(I\) = \[\]: .* value 50 out of bound 8>             abc(3:50) = []
+%!error <a null assignment can only have one non-colon index>   abc(3,5) = []
+%!error <=: nonconformant arguments \(op1 is 1x1, op2 is 1x5\)> abc(3,5) = 1:5
+
+%! ##  Test diagonal matrices, and access of function results
+%!error <index \(_,_,5\); but object has size 3x3> eye(3)(2,3,5)
+%!error <index \(-2,_\); subscripts>               eye(4)(-2,3)
+
+%! ##  Test cells
+%!shared abc
+%! abc = {1, 2; 3, 4};
+%!error <abc\(_,0.3,_\); subscripts>  abc(2,0.3,5)
+%!error <abc\(_,0.3,_\); subscripts>  abc{2,0.3,5}
+%!error <abc\(-2,_,_,_\); subscripts> abc{-2,1,1,1}
+%!error <abc\(0,_,_,_\); subscripts>  abc(0,1,1,1) = 1
+
+%! ##  Test permutation matrices
+%!shared abc
+%! abc = eye(3)([3 1 2],:);
+%!error <abc\(nan\); subscripts>         abc(NA)
+%!error <abc\(_,_,_,inf,_\); subscripts> abc(1,1,1,Inf,1)
+
+%! ##  Test sparse matrices
+%!shared abc
+%! abc = sparse(3,3);
+%!error <abc\(-1\); subscripts>                abc(-1)
+%!error <abc\(-1\); subscripts>                abc(-1) = 1
+%!error <abc\(-1,_\); subscripts>              abc(-1,1)
+%!error <abc\(-1,_\); subscripts>              abc(-1,1) = 1
+%!error <sparse indexing needs 1 or 2 indices> abc(0,0,0,0)
+%!error <abc\(4,_\); but abc has size 3x3>     abc(4,1)
+
+%! ##  Test ranges
+%!shared abc
+%! abc = 1:10;
+%!error <abc\(-1\); subscripts>             abc(-1)
+%!error <abc\(-1,_\); subscripts>           abc(-1,1)
+%!error <abc\(4,_\); but abc has size 1x10> abc(4,1)
+
+%! ##  Test complex
+%!shared abc, z
+%! abc = [1 2];
+%!error <abc\(0\+1i\); subscripts must be real>     abc(i)
+%! abc = [1 2; 3 4];
+%!error <abc\(1\+0i\); subscripts must be real>     abc(complex(1))
+%!error <abc\(1\+0.5i,_\); subscripts must be real> abc(1+0.5*i,3)
+%!error <abc\(_,0-2i\); subscripts must be real>   abc(2,0-2*i)
+
