diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,17 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [0.5.0] - 2018-05-15
+
+### Changed
+
+- Update the parser to `megaparsec 6.*`
+- Raise `protolude` minimal version to `0.2.*`
+
+### Fixed
+
+- Import missing quickcheck `NonEmpty` instances from `quickcheck-orphans`
+
 ## [0.4.0] - 2017-10-07
 
 ### Changed
diff --git a/src/Data/MultiKeyedMap.hs b/src/Data/MultiKeyedMap.hs
--- a/src/Data/MultiKeyedMap.hs
+++ b/src/Data/MultiKeyedMap.hs
@@ -32,6 +32,7 @@
 import qualified Data.List.NonEmpty as NE
 import Data.Proxy (Proxy(..))
 import qualified Data.Tuple as Tuple
+import GHC.Stack (HasCallStack)
 import qualified Text.Show as Show
 
 -- TODO: add time behaviour of functions to docstrings
@@ -87,10 +88,10 @@
   {-# INLINE traverse #-}
 
 -- | Find value at key. Partial. See 'M.!'.
-at :: (Ord k) => MKMap k v -> k -> v
+at :: (HasCallStack, Ord k) => MKMap k v -> k -> v
 at MKMap{keyMap, valMap} k =  valMap M.! (keyMap M.! k)
 -- | Operator alias of 'at'.
-(!) :: (Ord k) => MKMap k v -> k -> v
+(!) :: (HasCallStack, Ord k) => MKMap k v -> k -> v
 (!) = at
 {-# INLINABLE (!) #-}
 {-# INLINABLE at #-}
diff --git a/src/Yarn/Lock/File.hs b/src/Yarn/Lock/File.hs
--- a/src/Yarn/Lock/File.hs
+++ b/src/Yarn/Lock/File.hs
@@ -20,7 +20,7 @@
 , ConversionError(..)
 ) where
 
-import Protolude
+import Protolude hiding (hash, getField)
 import qualified Data.List.NonEmpty as NE
 import qualified Data.Map.Strict as M
 import qualified Data.Text as Text
diff --git a/src/Yarn/Lock/Helpers.hs b/src/Yarn/Lock/Helpers.hs
--- a/src/Yarn/Lock/Helpers.hs
+++ b/src/Yarn/Lock/Helpers.hs
@@ -15,6 +15,7 @@
 
 import Protolude
 import qualified Data.List as L
+import GHC.Stack (HasCallStack)
 
 import qualified Data.MultiKeyedMap as MKM
 
@@ -26,7 +27,11 @@
 -- Node packages often contain those and the yarn lockfile
 -- does not yet eliminate them, which may lead to infinite
 -- recursions.
-decycle :: Lockfile -> Lockfile
+--
+-- Invariant: Every dependency entry in each package in the
+-- 'Lockfile' *must* point to an existing key, otherwise
+-- the function crashes.
+decycle :: HasCallStack => Lockfile -> Lockfile
 decycle lf = goFold [] lf (MKM.keys lf)
   -- TODO: probably rewrite with State
   where
diff --git a/src/Yarn/Lock/Parse.hs b/src/Yarn/Lock/Parse.hs
--- a/src/Yarn/Lock/Parse.hs
+++ b/src/Yarn/Lock/Parse.hs
@@ -17,26 +17,28 @@
 , packageEntry
 -- * Internal Parsers
 , field, nestedField, simpleField
-, packageKeys, packageKey
+, packageKeys
 ) where
 
-import Protolude hiding (try)
+import Protolude hiding (try, some, many)
 import qualified Data.Char as Ch
 import qualified Data.List.NonEmpty as NE
 import qualified Data.Text as T
 import qualified Data.Map.Strict as M
 import Control.Monad (fail)
 
-import Text.Megaparsec as MP hiding (space)
-import Text.Megaparsec.Text
-import qualified Text.Megaparsec.Lexer as MPL
+import Text.Megaparsec as MP
+import qualified Text.Megaparsec.Char as MP
+import qualified Text.Megaparsec.Char.Lexer as MPL
 
 -- import qualified Data.MultiKeyedMap as MKM
 -- import Data.Proxy (Proxy(..))
 
 import qualified Yarn.Lock.Types as YLT
 
+type Parser = Parsec Void Text
 
+
 -- | The @yarn.lock@ format doesn’t specifically include a fixed scheme,
 -- it’s just an unnecessary custom version of a list of fields.
 --
@@ -54,8 +56,10 @@
 -- | Parse a complete yarn.lock into an abstract syntax tree,
 -- keeping the source positions of each package entry.
 packageList :: Parser [Package]
-packageList = many $ (skipMany (comment <|> eol)) *> packageEntry
-                where comment = char '#' *> manyTill anyChar eol
+packageList = MP.many $ (skipMany (comment <|> MP.string "\n")) *> packageEntry
+                where
+                  comment :: Parser (Tokens Text)
+                  comment = MP.char '#' *> takeWhileP Nothing (/= '\n')
 
 -- | A single Package.
 --
@@ -90,8 +94,8 @@
 -- @
 packageKeys :: Parser (NE.NonEmpty YLT.PackageKey)
 packageKeys = label "package keys" $ do
-  firstEls <- many (try $ lexeme $ packageKey ":," <* char ',')
-  lastEl   <-                      packageKey ":"  <* char ':'
+  firstEls <- many (try $ lexeme $ packageKey ":," <* MP.char ',')
+  lastEl   <-                      packageKey ":"  <* MP.char ':'
   pure $ NE.fromList $ firstEls <> [lastEl]
 
 -- | A packageKey is @\<package-name\>\@\<semver\>@;
@@ -106,7 +110,7 @@
   where
     pkgKey :: [Char] -> Parser YLT.PackageKey
     pkgKey valueChars = label "package key" $ do
-      key <- someTextOf (noneOf valueChars)
+      key <- someTextOf (MP.noneOf valueChars)
       -- okay, here’s the rub:
       -- `@` is used for separation, but package names containing `@`
       -- are totally a thing. As first character, as well.
@@ -136,7 +140,7 @@
                   <?> "simple field"
   where
     valueChars, strValueChars :: Parser Text
-    valueChars = someTextOf (noneOf ("\n\r\"" :: [Char]))
+    valueChars = someTextOf (MP.noneOf ("\n\r\"" :: [Char]))
     strSymbolChars = inString $ symbolChars
     strValueChars = inString $ valueChars
       -- as with packageKey semvers, this can be empty
@@ -146,7 +150,7 @@
 -- we get another block with deeper indentation.
 nestedField :: Parser (Text, PackageFields)
 nestedField = label "nested field" $
-  indentedFieldsWithHeader (symbolChars <* char ':')
+  indentedFieldsWithHeader (symbolChars <* MP.char ':')
 
 
 -- internal parsers
@@ -172,7 +176,7 @@
 -- Update: npm doesn’t specify the package name format, at all.
 -- Apart from the length.
 symbolChars :: Parser Text
-symbolChars = label "key symbol" $ someTextOf $ satisfy
+symbolChars = label "key symbol" $ someTextOf $ MP.satisfy
   (\c -> Ch.isAscii c &&
      (Ch.isLower c || Ch.isUpper c || Ch.isNumber c || c `elem` special))
   where special = "-_.@/" :: [Char]
@@ -185,7 +189,7 @@
 
 -- | parse everything as inside a string
 inString :: Parser a -> Parser a
-inString = between (char '"') (char '"')
+inString = between (MP.char '"') (MP.char '"')
 
 -- lexers
 
@@ -193,7 +197,7 @@
 space :: Parser ()
 space = MPL.space (void MP.spaceChar)
                   (MPL.skipLineComment "# ")
-                  (void $ satisfy (const False))
+                  (void $ MP.satisfy (const False))
 
 -- | Parse a lexeme.
 lexeme :: Parser a -> Parser a
@@ -202,6 +206,6 @@
 -- | Ensure parser is not indented.
 nonIndented :: Parser a -> Parser a
 nonIndented = MPL.nonIndented space
-indentBlock :: ParsecT Dec Text Identity (MPL.IndentOpt (ParsecT Dec Text Identity) a b)
-            -> ParsecT Dec Text Identity a
+indentBlock :: Parser (MPL.IndentOpt Parser a b)
+            -> Parser a
 indentBlock = MPL.indentBlock space
diff --git a/tests/TestFile.hs b/tests/TestFile.hs
--- a/tests/TestFile.hs
+++ b/tests/TestFile.hs
@@ -64,15 +64,10 @@
     (File.MissingField "version"
      NE.:| [File.UnknownRemoteType]) $ emptyAst []
 
--- will be in protolude soon
-infixl 4 <&>
-(<&>) :: Functor f => f a -> (a -> b) -> f b
-(<&>) = flip fmap
-
 astToPackageSuccess :: Parse.PackageFields -> IO T.Package
 astToPackageSuccess ast = case File.astToPackage ast of
   (Left errs) -> do
-     assertFailure ("should have succeded, but:\n" <> show errs)
+     _ <- assertFailure ("should have succeded, but:\n" <> show errs)
      panic "not reached"
   (Right pkg) -> pure pkg
 
diff --git a/tests/TestMultiKeyedMap.hs b/tests/TestMultiKeyedMap.hs
--- a/tests/TestMultiKeyedMap.hs
+++ b/tests/TestMultiKeyedMap.hs
@@ -7,6 +7,7 @@
 import Test.Tasty (TestTree)
 import Test.Tasty.TH
 import Test.Tasty.QuickCheck
+import Test.QuickCheck.Instances () -- orphans!
 
 import qualified Data.MultiKeyedMap as MKM
 
diff --git a/tests/TestParse.hs b/tests/TestParse.hs
--- a/tests/TestParse.hs
+++ b/tests/TestParse.hs
@@ -14,6 +14,21 @@
 import Yarn.Lock.Types
 import Yarn.Lock.Parse
 
+startComment :: Text
+startComment = [text|
+  # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+  # yarn lockfile v1
+  dummy-package@foo:
+    version: foo
+  |]
+
+case_startCommentEmptyPackageList :: Assertion
+case_startCommentEmptyPackageList = do
+  parseSuccess packageList startComment
+    >>= \((Keyed keys _) : _) -> do
+      assertBool "only foo"
+        (keys == pure (PackageKey "dummy-package" "foo"))
+
 -- registryPackage :: Text
 -- registryPackage = [text|
 --   accepts@1.3.3, accepts@~1.3.3:
@@ -114,7 +129,7 @@
   case MP.parse parser "" string of
     (Right a) -> pure a
     (Left err) -> do
-      assertFailure ("parse should succeed, but: \n"
+      _ <- assertFailure ("parse should succeed, but: \n"
                     <> MP.parseErrorPretty err
                     <> "for input\n" <> toS string <> "\n\"")
       panic "not reached"
diff --git a/yarn-lock.cabal b/yarn-lock.cabal
--- a/yarn-lock.cabal
+++ b/yarn-lock.cabal
@@ -1,9 +1,11 @@
--- This file has been generated from package.yaml by hpack version 0.18.1.
+-- This file has been generated from package.yaml by hpack version 0.27.0.
 --
 -- see: https://github.com/sol/hpack
+--
+-- hash: bfe08f55682f41944db8ec965c30c279fd7d244188df301b7d3d22a65d0c9df7
 
 name:           yarn-lock
-version:        0.4.0
+version:        0.4.1
 synopsis:       Represent and parse yarn.lock files
 description:    Types and parser for the lock file format of the npm successor yarn. All modules should be imported qualified.
 category:       Data
@@ -24,16 +26,6 @@
   location: https://github.com/Profpatsch/yarn-lock
 
 library
-  hs-source-dirs:
-      src
-  ghc-options: -Wall
-  build-depends:
-      base == 4.9.*
-    , containers
-    , text
-    , megaparsec == 5.*
-    , protolude == 0.1.* || == 0.2.*
-    , either == 4.*
   exposed-modules:
       Data.MultiKeyedMap
       Yarn.Lock
@@ -43,31 +35,42 @@
       Yarn.Lock.Types
   other-modules:
       Paths_yarn_lock
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      base ==4.*
+    , containers
+    , either >=4 && <6
+    , megaparsec ==6.*
+    , protolude ==0.2.*
+    , text
   default-language: Haskell2010
 
 test-suite yarn-lock-tests
   type: exitcode-stdio-1.0
   main-is: Test.hs
+  other-modules:
+      TestFile
+      TestMultiKeyedMap
+      TestParse
+      Paths_yarn_lock
   hs-source-dirs:
       tests
   ghc-options: -Wall
   build-depends:
-      base == 4.9.*
+      ansi-wl-pprint >=0.6
+    , base ==4.*
     , containers
+    , either >=4 && <6
+    , megaparsec ==6.*
+    , neat-interpolation >=0.3
+    , protolude
+    , quickcheck-instances ==0.3.*
+    , tasty >=0.11
+    , tasty-hunit >=0.9
+    , tasty-quickcheck >=0.8
+    , tasty-th >=0.1.7
     , text
-    , megaparsec == 5.*
-    , protolude == 0.1.* || == 0.2.*
-    , either == 4.*
     , yarn-lock
-    , ansi-wl-pprint >= 0.6
-    , tasty >= 0.11
-    , tasty-th >= 0.1.7
-    , tasty-hunit >= 0.9
-    , tasty-quickcheck >= 0.8
-    , protolude
-    , neat-interpolation >= 0.3
-  other-modules:
-      TestFile
-      TestMultiKeyedMap
-      TestParse
   default-language: Haskell2010
