diff --git a/Swish/RDF/N3Parser.hs b/Swish/RDF/N3Parser.hs
--- a/Swish/RDF/N3Parser.hs
+++ b/Swish/RDF/N3Parser.hs
@@ -111,6 +111,7 @@
 import Swish.RDF.RDFParser
     ( SpecialMap
     , ParseResult
+    , runParserWithError
     -- , mapPrefix
     , prefixTable
     , specialTable
@@ -241,6 +242,24 @@
 hashURI :: URI
 hashURI = fromJust $ parseURIReference "#"
 
+emptyState :: 
+  Maybe QName  -- ^ starting base for the graph
+  -> N3State
+emptyState mbase = 
+  let pmap   = LookupMap [makeNamespace Nothing hashURI]
+      muri   = fmap (makeQNameScopedName Nothing) mbase
+      smap   = LookupMap $ specialTable muri
+  in N3State
+     { graphState = emptyRDFGraph
+     , thisNode   = NoNode
+     , prefixUris = pmap
+     , syntaxUris = smap
+     , nodeGen    = 0
+     , keywordsList = ["a", "is", "of", "true", "false"] -- not 100% sure about true/false here
+     , allowLocalNames = False
+     }
+
+
 -- TODO: change from QName to URI for the base?
 
 -- | Function to supply initial context and parse supplied term.
@@ -249,23 +268,7 @@
                     -> Maybe QName  -- ^ base URI of the input, or @Nothing@ to use default base value
                     -> L.Text       -- ^ input to be parsed
                     -> Either String a
-parseAnyfromText parser mbase input =
-  let pmap   = LookupMap [makeNamespace Nothing hashURI]
-      muri   = fmap (makeQNameScopedName Nothing) mbase
-      smap   = LookupMap $ specialTable muri
-      pstate = N3State
-              { graphState = emptyRDFGraph
-              , thisNode   = NoNode
-              , prefixUris = pmap
-              , syntaxUris = smap
-              , nodeGen    = 0
-              , keywordsList = ["a", "is", "of", "true", "false"] -- not 100% sure about true/false here
-              , allowLocalNames = False
-              }
-  
-      (result, _, _) = runParser parser pstate input
-     
-  in result
+parseAnyfromText parser mbase = runParserWithError parser (emptyState mbase)
 
 newBlankNode :: N3Parser RDFLabel
 newBlankNode = do
diff --git a/Swish/RDF/NTParser.hs b/Swish/RDF/NTParser.hs
--- a/Swish/RDF/NTParser.hs
+++ b/Swish/RDF/NTParser.hs
@@ -54,6 +54,7 @@
 import Swish.RDF.Vocabulary (langName)
 
 import Swish.RDF.RDFParser ( ParseResult
+    , runParserWithError
     , ignore
     , skipMany
     , noneOf
@@ -94,6 +95,9 @@
         { graphState :: RDFGraph            -- Graph under construction
         }
 
+emptyState :: NTState
+emptyState = NTState { graphState = emptyRDFGraph }
+           
 --  Return function to update graph in NT parser state,
 --  using the supplied function of a graph. This is for use
 --  with stUpdate.
@@ -136,13 +140,8 @@
     NTParser a      -- ^ parser to apply
     -> L.Text       -- ^ input to be parsed
     -> Either String a
-parsefromText parser input =
-        let istate = NTState
-                    { graphState = emptyRDFGraph
-                    }
-            (result, _, _) = runParser parser istate input
-        in result 
-           
+parsefromText parser = runParserWithError parser emptyState
+
 -- helper routines
 
 {-
diff --git a/Swish/RDF/RDFParser.hs b/Swish/RDF/RDFParser.hs
--- a/Swish/RDF/RDFParser.hs
+++ b/Swish/RDF/RDFParser.hs
@@ -23,6 +23,7 @@
     , prefixTable, specialTable
 
     -- parser
+    , runParserWithError
     , ParseResult
     , ignore
     , char
@@ -141,7 +142,32 @@
     ("base",      fromMaybe defaultBase mbase ) 
   ]
 
--- Parser routines, heavily based on Parsec
+-- Parser routines, heavily based on Parsec combinators
+
+-- | Run the parser and return the successful parse or an error
+-- message which consists of the standard Polyparse error plus
+-- a fragment of the unparsed input to provide context.
+--
+runParserWithError :: 
+  Parser a b -- ^ parser (carrying state) to apply
+  -> a       -- ^ starting state for the parser
+  -> L.Text       -- ^ input to be parsed
+  -> Either String b
+runParserWithError parser state0 input = 
+  let (result, _, unparsed) = runParser parser state0 input
+     
+      -- TODO: work out how best to report error context; for now just take the
+      -- next 40 characters and assume there is enough context.
+      econtext = if L.null unparsed
+                 then "\n(at end of the text)\n"
+                 else "\nRemaining input:\n" ++ 
+                      case L.compareLength unparsed 40 of
+                        GT -> L.unpack (L.take 40 unparsed) ++ "..."
+                        _ -> L.unpack unparsed
+
+  in case result of
+    Left emsg -> Left $ emsg ++ econtext
+    _ -> result
 
 type ParseResult = Either String RDFGraph
 
diff --git a/Swish/RDF/TurtleParser.hs b/Swish/RDF/TurtleParser.hs
--- a/Swish/RDF/TurtleParser.hs
+++ b/Swish/RDF/TurtleParser.hs
@@ -89,12 +89,8 @@
 
 import Swish.RDF.RDFParser
     ( ParseResult
-    -- , prefixTable
+    , runParserWithError
     , ignore
-    -- , notFollowedBy
-    -- , endBy
-    -- , sepEndBy
-    -- , manyTill
     , noneOf
     , char
     , ichar
@@ -214,18 +210,12 @@
   
 -- | Function to supply initial context and parse supplied term.
 --
-parseAnyfromText :: TurtleParser a  -- ^ parser to apply
-                    -> Maybe URI    -- ^ base URI of the input, or @Nothing@ to use default base value
-                    -> L.Text       -- ^ input to be parsed
-                    -> Either String a
-parseAnyfromText parser mbase input =
-  let (result, _, unparsed) = runParser parser (emptyState mbase) input
-     
-      -- TODO: work out how best to report error context.
-      
-  in case result of
-    Left emsg -> Left $ concat [emsg, "\nRemaining input:\n", L.unpack unparsed]
-    _ -> result
+parseAnyfromText :: 
+  TurtleParser a  -- ^ parser to apply
+  -> Maybe URI    -- ^ base URI of the input, or @Nothing@ to use default base value
+  -> L.Text       -- ^ input to be parsed
+  -> Either String a
+parseAnyfromText parser mbase = runParserWithError parser (emptyState mbase)
 
 newBlankNode :: TurtleParser RDFLabel
 newBlankNode = do
diff --git a/swish.cabal b/swish.cabal
--- a/swish.cabal
+++ b/swish.cabal
@@ -1,5 +1,5 @@
 Name:               swish
-Version:            0.6.1.0
+Version:            0.6.1.1
 Stability:          experimental
 License:            LGPL
 License-file:       LICENSE 
@@ -45,6 +45,11 @@
   * Complete, ready-to-run, command-line and script-driven programs.
   .
   Changes:
+  .
+  [Version 0.6.1.1] Minor improvement to the error message produced by the
+  Turtle, Ntriples, and N3 parsers: a fragment of the remaining text is
+  included to provide some context (still lacking compared to the information
+  provided in version 0.3.2.1).
   .
   [Version 0.6.1.0] Added support for Turtle format (added the
   Swish.RDF.TurtleFormatter and Swish.RDF.TurtleParser modules).
diff --git a/tests/N3ParserTest.hs b/tests/N3ParserTest.hs
--- a/tests/N3ParserTest.hs
+++ b/tests/N3ParserTest.hs
@@ -65,6 +65,7 @@
 
 import Data.Monoid (Monoid(..))
 import Data.Maybe (fromMaybe)
+import Data.List (intercalate)
 
 import qualified Data.Text as T
 import qualified Data.Text.Lazy as L
@@ -1163,7 +1164,7 @@
   "expecting declaration, \"@\", pathitem or end of input"
   ]
 -}
-emsg16 = "Expected end of input (EOF)"
+emsg16 = "Expected end of input (EOF)\nRemaining input:\n**** "
 
 simpleTestSuite :: Test
 simpleTestSuite = TestList
@@ -1469,7 +1470,11 @@
          "unexpected Prefix 'unknown3:' not bound."
         ]
 -}
-fail1 = "When looking for a non-empty sequence with separators:\n\tPrefix 'unknown3:' not bound."
+fail1 = intercalate "\n" 
+        ["When looking for a non-empty sequence with separators:"
+        , "\tPrefix 'unknown3:' not bound."
+        , "Remaining input:"
+        , "o3 . "]
 
 failTestSuite :: Test
 failTestSuite = TestList
