diff --git a/src/swcio.cpp b/src/swcio.cpp
index e87eaa1846458f9d00d9b97e7c8c3de4bfc54a2a..32724fe8f38685a593c6d82cdbf27448c26a325a 100644
--- a/src/swcio.cpp
+++ b/src/swcio.cpp
@@ -13,7 +13,7 @@ namespace io
 
 //
 // cell_record implementation
-// 
+//
 void cell_record::renumber(id_type new_id, std::map<id_type, id_type> &idmap)
 {
     auto old_id = id_;
@@ -79,26 +79,26 @@ std::ostream &operator<<(std::ostream &os, const cell_record &cell)
 
 //
 // Utility functions
-// 
+//
 
 bool starts_with(const std::string &str, const std::string &prefix)
 {
     return (str.find(prefix) == 0);
 }
 
-void check_parse_status(const std::istream &is)
+void check_parse_status(const std::istream &is, const swc_parser &parser)
 {
     if (is.fail()) {
         // If we try to read past the eof; fail bit will also be set
-        throw swc_parse_error("could not parse value");
+        throw swc_parse_error("could not parse value", parser.lineno());
     }
 }
 
 template<typename T>
-T parse_value_strict(std::istream &is)
+T parse_value_strict(std::istream &is, const swc_parser &parser)
 {
     T val;
-    check_parse_status(is >> val);
+    check_parse_status(is >> val, parser);
 
     // everything's fine
     return val;
@@ -106,10 +106,10 @@ T parse_value_strict(std::istream &is)
 
 // specialize parsing for cell types
 template<>
-cell_record::kind parse_value_strict(std::istream &is)
+cell_record::kind parse_value_strict(std::istream &is, const swc_parser &parser)
 {
     cell_record::id_type val;
-    check_parse_status(is >> val);
+    check_parse_status(is >> val, parser);
 
     // Let cell_record's constructor check for the type validity
     return static_cast<cell_record::kind>(val);
@@ -117,13 +117,14 @@ cell_record::kind parse_value_strict(std::istream &is)
 
 //
 // swc_parser implementation
-// 
+//
 
 std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell)
 {
     while (!is.eof() && !is.bad()) {
         // consume empty and comment lines first
         std::getline(is, linebuff_);
+        ++lineno_;
         if (!linebuff_.empty() && !starts_with(linebuff_, comment_prefix_))
             break;
     }
@@ -140,23 +141,29 @@ std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell)
     }
 
     if (is.fail()) {
-        throw swc_parse_error("too long line detected");
+        throw swc_parse_error("too long line detected", lineno_);
     }
 
     std::istringstream line(linebuff_);
-    cell = parse_record(line);
+    try {
+        cell = parse_record(line);
+    } catch (std::invalid_argument &e) {
+        // Rethrow as a parse error
+        throw swc_parse_error(e.what(), lineno_);
+    }
+
     return is;
 }
 
 cell_record swc_parser::parse_record(std::istringstream &is)
 {
-    auto id = parse_value_strict<int>(is);
-    auto type = parse_value_strict<cell_record::kind>(is);
-    auto x = parse_value_strict<float>(is);
-    auto y = parse_value_strict<float>(is);
-    auto z = parse_value_strict<float>(is);
-    auto r = parse_value_strict<float>(is);
-    auto parent_id = parse_value_strict<cell_record::id_type>(is);
+    auto id = parse_value_strict<int>(is, *this);
+    auto type = parse_value_strict<cell_record::kind>(is, *this);
+    auto x = parse_value_strict<float>(is, *this);
+    auto y = parse_value_strict<float>(is, *this);
+    auto z = parse_value_strict<float>(is, *this);
+    auto r = parse_value_strict<float>(is, *this);
+    auto parent_id = parse_value_strict<cell_record::id_type>(is, *this);
 
     // Convert to zero-based, leaving parent_id as-is if -1
     if (parent_id != -1) {
diff --git a/src/swcio.hpp b/src/swcio.hpp
index 0348eb4f149303362c736d885afae8d1d77c2eb5..5365c8a5b508f6102e06c08d780cd94a64aeae0b 100644
--- a/src/swcio.hpp
+++ b/src/swcio.hpp
@@ -166,13 +166,23 @@ private:
 class swc_parse_error : public std::runtime_error
 {
 public:
-    explicit swc_parse_error(const char *msg)
+    explicit swc_parse_error(const char *msg, std::size_t lineno)
         : std::runtime_error(msg)
+        , lineno_(lineno)
     { }
 
-    explicit swc_parse_error(const std::string &msg)
+    explicit swc_parse_error(const std::string &msg, std::size_t lineno)
         : std::runtime_error(msg)
+        , lineno_(lineno)
     { }
+
+    std::size_t lineno() const
+    {
+        return lineno_;
+    }
+
+private:
+    std::size_t lineno_;
 };
 
 class swc_parser
@@ -182,13 +192,20 @@ public:
                std::string comment_prefix)
         : delim_(delim)
         , comment_prefix_(comment_prefix)
+        , lineno_(0)
     { }
 
     swc_parser()
         : delim_(" ")
         , comment_prefix_("#")
+        , lineno_(0)
     { }
 
+    std::size_t lineno() const
+    {
+        return lineno_;
+    }
+
     std::istream &parse_record(std::istream &is, cell_record &cell);
 
 private:
@@ -198,6 +215,7 @@ private:
     std::string delim_;
     std::string comment_prefix_;
     std::string linebuff_;
+    std::size_t lineno_;
 };
 
 
diff --git a/tests/test_swcio.cpp b/tests/test_swcio.cpp
index 5912a1e5086bfe6a25120bf2dcfe72ccd6e9f1ba..16e6de8c4eb0d7a9b7c7de6264ba66a4f7f7a192 100644
--- a/tests/test_swcio.cpp
+++ b/tests/test_swcio.cpp
@@ -129,7 +129,7 @@ TEST(swc_parser, invalid_input)
         std::istringstream is(
             "1 10 14.566132 34.873772 7.857000 0.717830 -1\n");
         cell_record cell;
-        EXPECT_THROW(is >> cell, std::invalid_argument);
+        EXPECT_THROW(is >> cell, swc_parse_error);
     }
 }
 
@@ -340,12 +340,12 @@ TEST(cell_record_ranges, raw)
     }
 
     {
+        // Check iterator increments
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
 
-        // Check postfix operator++
         auto iter = get_cell_records<swc_io_raw>(is).begin();
-        auto iend   = get_cell_records<swc_io_raw>(is).end();
+        auto iend = get_cell_records<swc_io_raw>(is).end();
 
         cell_record c;
         EXPECT_NO_THROW(c = *iter++);
@@ -355,4 +355,24 @@ TEST(cell_record_ranges, raw)
         // Try to read past eof
         EXPECT_THROW(*iter, std::out_of_range);
     }
+
+    {
+        // Check parse error context
+        std::stringstream is;
+        is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
+        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "3 10 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+
+        std::vector<cell_record> cells;
+        try {
+            for (auto c : get_cell_records<swc_io_raw>(is)) {
+                cells.push_back(c);
+            }
+
+            FAIL() << "expected an exception";
+        } catch (const swc_parse_error &e) {
+            EXPECT_EQ(3u, e.lineno());
+        }
+    }
 }