use pkg:checked_yaml
diff --git a/pkgs/pubspec_parse/lib/pubspec_parse.dart b/pkgs/pubspec_parse/lib/pubspec_parse.dart
index 99886c4..132263a 100644
--- a/pkgs/pubspec_parse/lib/pubspec_parse.dart
+++ b/pkgs/pubspec_parse/lib/pubspec_parse.dart
@@ -9,5 +9,4 @@
         GitDependency,
         SdkDependency,
         PathDependency;
-export 'src/errors.dart' show ParsedYamlException;
 export 'src/pubspec.dart' show Pubspec;
diff --git a/pkgs/pubspec_parse/lib/src/dependency.dart b/pkgs/pubspec_parse/lib/src/dependency.dart
index 364e703..e2b0770 100644
--- a/pkgs/pubspec_parse/lib/src/dependency.dart
+++ b/pkgs/pubspec_parse/lib/src/dependency.dart
@@ -47,20 +47,21 @@
     if (data.isEmpty || (matchedKeys.isEmpty && data.containsKey('version'))) {
       return _$HostedDependencyFromJson(data);
     } else {
-      final weirdKey = matchedKeys.firstWhere((k) => !_sourceKeys.contains(k),
-          orElse: () => null);
+      final firstUnrecognizedKey = matchedKeys
+          .firstWhere((k) => !_sourceKeys.contains(k), orElse: () => null);
 
-      if (weirdKey != null) {
-        throw UnrecognizedKeysException([weirdKey], data, _sourceKeys);
-      }
-      if (matchedKeys.length > 1) {
-        throw CheckedFromJsonException(data, matchedKeys[1], 'Dependency',
-            'A dependency may only have one source.');
-      }
+      return $checkedNew<Dependency>('Dependency', data, () {
+        if (firstUnrecognizedKey != null) {
+          throw UnrecognizedKeysException(
+              [firstUnrecognizedKey], data, _sourceKeys);
+        }
+        if (matchedKeys.length > 1) {
+          throw CheckedFromJsonException(data, matchedKeys[1], 'Dependency',
+              'A dependency may only have one source.');
+        }
 
-      final key = matchedKeys.single;
+        final key = matchedKeys.single;
 
-      try {
         switch (key) {
           case 'git':
             return GitDependency.fromData(data[key]);
@@ -72,10 +73,7 @@
             return _$HostedDependencyFromJson(data);
         }
         throw StateError('There is a bug in pubspec_parse.');
-      } on ArgumentError catch (e) {
-        throw CheckedFromJsonException(
-            data, e.name, 'Dependency', e.message.toString());
-      }
+      });
     }
   }
 
diff --git a/pkgs/pubspec_parse/lib/src/errors.dart b/pkgs/pubspec_parse/lib/src/errors.dart
deleted file mode 100644
index 6d2b38c..0000000
--- a/pkgs/pubspec_parse/lib/src/errors.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:json_annotation/json_annotation.dart';
-import 'package:yaml/yaml.dart';
-
-ParsedYamlException parsedYamlException(String message, YamlNode yamlNode) =>
-    ParsedYamlException._(message, yamlNode);
-
-ParsedYamlException parsedYamlExceptionFromError(
-    CheckedFromJsonException error, StackTrace stack) {
-  final innerError = error.innerError;
-  if (innerError is UnrecognizedKeysException) {
-    final map = innerError.map;
-    if (map is YamlMap) {
-      // if the associated key exists, use that as the error node,
-      // otherwise use the map itself
-      final node = map.nodes.keys.cast<YamlNode>().firstWhere((key) {
-        return innerError.unrecognizedKeys.contains(key.value);
-      }, orElse: () => map);
-
-      return ParsedYamlException._(innerError.message, node,
-          innerError: error, innerStack: stack);
-    }
-  } else if (innerError is ParsedYamlException) {
-    return innerError;
-  }
-
-  final yamlMap = error.map as YamlMap;
-  var yamlNode = yamlMap.nodes[error.key];
-
-  String message;
-  if (yamlNode == null) {
-    assert(error.message != null);
-    message = error.message;
-    yamlNode = yamlMap;
-  } else {
-    if (error.message == null) {
-      message = 'Unsupported value for `${error.key}`.';
-    } else {
-      message = error.message.toString();
-    }
-  }
-
-  return ParsedYamlException._(message, yamlNode,
-      innerError: error, innerStack: stack);
-}
-
-/// Thrown when parsing a YAML document fails.
-class ParsedYamlException implements Exception {
-  /// Describes the nature of the parse failure.
-  final String message;
-
-  final YamlNode yamlNode;
-
-  /// If this exception was thrown as a result of another error,
-  /// contains the source error object.
-  final Object innerError;
-
-  /// If this exception was thrown as a result of another error,
-  /// contains the corresponding [StackTrace].
-  final StackTrace innerStack;
-
-  ParsedYamlException._(this.message, this.yamlNode,
-      {this.innerError, this.innerStack});
-
-  /// Returns [message] formatted with source information provided by
-  /// [yamlNode].
-  String get formattedMessage => yamlNode.span.message(message);
-
-  @override
-  String toString() => message;
-}
diff --git a/pkgs/pubspec_parse/lib/src/pubspec.dart b/pkgs/pubspec_parse/lib/src/pubspec.dart
index a8dacf6..d31e657 100644
--- a/pkgs/pubspec_parse/lib/src/pubspec.dart
+++ b/pkgs/pubspec_parse/lib/src/pubspec.dart
@@ -4,10 +4,9 @@
 
 import 'package:json_annotation/json_annotation.dart';
 import 'package:pub_semver/pub_semver.dart';
-import 'package:yaml/yaml.dart';
+import 'package:checked_yaml/checked_yaml.dart';
 
 import 'dependency.dart';
-import 'errors.dart';
 
 part 'pubspec.g.dart';
 
@@ -108,7 +107,7 @@
       try {
         final targetUri = Uri.parse(publishTo);
         if (!(targetUri.isScheme('http') || targetUri.isScheme('https'))) {
-          throw const FormatException('must be an http or https URL.');
+          throw const FormatException('Must be an http or https URL.');
         }
       } on FormatException catch (e) {
         throw ArgumentError.value(publishTo, 'publishTo', e.message);
@@ -144,25 +143,9 @@
   factory Pubspec.parse(String yaml, {sourceUrl, bool lenient = false}) {
     lenient ??= false;
 
-    final item = loadYaml(yaml, sourceUrl: sourceUrl);
-
-    if (item == null) {
-      throw ArgumentError.notNull('yaml');
-    }
-
-    if (item is! YamlMap) {
-      if (item is YamlNode) {
-        throw parsedYamlException('Does not represent a YAML map.', item);
-      }
-
-      throw ArgumentError.value(yaml, 'yaml', 'Does not represent a YAML map.');
-    }
-
-    try {
-      return Pubspec.fromJson(item as YamlMap, lenient: lenient);
-    } on CheckedFromJsonException catch (error, stack) {
-      throw parsedYamlExceptionFromError(error, stack);
-    }
+    return checkedYamlDecode(
+        yaml, (map) => Pubspec.fromJson(map, lenient: lenient),
+        sourceUrl: sourceUrl);
   }
 
   static List<String> _normalizeAuthors(String author, List<String> authors) {
@@ -185,7 +168,13 @@
       if (key == 'dart') {
         // github.com/dart-lang/pub/blob/d84173eeb03c3/lib/src/pubspec.dart#L342
         // 'dart' is not allowed as a key!
-        throw UnrecognizedKeysException(['dart'], source, ['sdk']);
+        throw CheckedFromJsonException(
+          source,
+          'dart',
+          'VersionConstraint',
+          'Use "sdk" to for Dart SDK constraints.',
+          badKey: true,
+        );
       }
 
       VersionConstraint constraint;
diff --git a/pkgs/pubspec_parse/pubspec.yaml b/pkgs/pubspec_parse/pubspec.yaml
index c1df008..2ae7fb2 100644
--- a/pkgs/pubspec_parse/pubspec.yaml
+++ b/pkgs/pubspec_parse/pubspec.yaml
@@ -10,6 +10,7 @@
   sdk: '>=2.2.0 <3.0.0'
 
 dependencies:
+  checked_yaml: ^1.0.0
   # Verified that no new features since 1.0.0 are used - be careful!
   json_annotation: '>=1.0.0 <3.0.0'
   pub_semver: ^1.3.2
diff --git a/pkgs/pubspec_parse/test/dependency_test.dart b/pkgs/pubspec_parse/test/dependency_test.dart
index 9e90997..9480105 100644
--- a/pkgs/pubspec_parse/test/dependency_test.dart
+++ b/pkgs/pubspec_parse/test/dependency_test.dart
@@ -18,32 +18,41 @@
 
   group('errors', () {
     test('List', () {
-      _expectThrows([], r'''
-line 4, column 10: Not a valid dependency value.
+      _expectThrows(
+        [],
+        r'''
+line 4, column 10: Unsupported value for "dep". Not a valid dependency value.

 4 │   "dep": []
   │          ^^
-  ╵''');
+  ╵''',
+      );
     });
 
     test('int', () {
-      _expectThrows(42, r'''
-line 4, column 10: Not a valid dependency value.
+      _expectThrows(
+        42,
+        r'''
+line 4, column 10: Unsupported value for "dep". Not a valid dependency value.

 4 │     "dep": 42
   │ ┌──────────^
 5 │ │  }
   │ └─^
-  ╵''');
+  ╵''',
+      );
     });
 
     test('map with too many keys', () {
-      _expectThrows({'path': 'a', 'git': 'b'}, r'''
-line 5, column 12: A dependency may only have one source.
+      _expectThrows(
+        {'path': 'a', 'git': 'b'},
+        r'''
+line 5, column 12: Unsupported value for "path". A dependency may only have one source.

 5 │    "path": "a",
   │            ^^^
-  ╵''');
+  ╵''',
+      );
     });
 
     test('map with unsupported keys', () {
@@ -79,12 +88,15 @@
   });
 
   test('bad string version', () {
-    _expectThrows('not a version', r'''
-line 4, column 10: Could not parse version "not a version". Unknown text at "not a version".
+    _expectThrows(
+      'not a version',
+      r'''
+line 4, column 10: Unsupported value for "dep". Could not parse version "not a version". Unknown text at "not a version".

 4 │   "dep": "not a version"
   │          ^^^^^^^^^^^^^^^
-  ╵''');
+  ╵''',
+    );
   });
 
   test('map w/ just version', () {
@@ -106,15 +118,18 @@
   });
 
   test('map w/ bad version value', () {
-    _expectThrows({
-      'version': 'not a version',
-      'hosted': {'name': 'hosted_name', 'url': 'hosted_url'}
-    }, r'''
-line 5, column 15: Could not parse version "not a version". Unknown text at "not a version".
+    _expectThrows(
+      {
+        'version': 'not a version',
+        'hosted': {'name': 'hosted_name', 'url': 'hosted_url'}
+      },
+      r'''
+line 5, column 15: Unsupported value for "version". Could not parse version "not a version". Unknown text at "not a version".

 5 │    "version": "not a version",
   │               ^^^^^^^^^^^^^^^
-  ╵''');
+  ╵''',
+    );
   });
 
   test('map w/ extra keys should fail', () {
@@ -148,14 +163,15 @@
   });
 
   test('map w/ null hosted should error', () {
-    _expectThrows({'hosted': null}, r'''
-line 5, column 14: These keys had `null` values, which is not allowed: [hosted]
+    _expectThrows(
+      {'hosted': null},
+      r'''
+line 5, column 4: These keys had `null` values, which is not allowed: [hosted]

-5 │      "hosted": null
-  │ ┌──────────────^
-6 │ │   }
-  │ └──^
-  ╵''');
+5 │    "hosted": null
+  │    ^^^^^^^^
+  ╵''',
+    );
   });
 
   test('map w/ null version is fine', () {
@@ -183,25 +199,29 @@
   });
 
   test('null content', () {
-    _expectThrows({'sdk': null}, r'''
-line 5, column 11: These keys had `null` values, which is not allowed: [sdk]
+    _expectThrows(
+      {'sdk': null},
+      r'''
+line 5, column 4: These keys had `null` values, which is not allowed: [sdk]

-5 │      "sdk": null
-  │ ┌───────────^
-6 │ │   }
-  │ └──^
-  ╵''');
+5 │    "sdk": null
+  │    ^^^^^
+  ╵''',
+    );
   });
 
   test('number content', () {
-    _expectThrows({'sdk': 42}, r'''
-line 5, column 11: Unsupported value for `sdk`.
+    _expectThrows(
+      {'sdk': 42},
+      r'''
+line 5, column 11: Unsupported value for "sdk".

 5 │      "sdk": 42
   │ ┌───────────^
 6 │ │   }
   │ └──^
-  ╵''');
+  ╵''',
+    );
   });
 }
 
@@ -256,25 +276,31 @@
   });
 
   test('git - null content', () {
-    _expectThrows({'git': null}, r'''
-line 5, column 11: Must be a String or a Map.
+    _expectThrows(
+      {'git': null},
+      r'''
+line 5, column 11: Unsupported value for "git". Must be a String or a Map.

 5 │      "git": null
   │ ┌───────────^
 6 │ │   }
   │ └──^
-  ╵''');
+  ╵''',
+    );
   });
 
   test('git - int content', () {
-    _expectThrows({'git': 42}, r'''
-line 5, column 11: Must be a String or a Map.
+    _expectThrows(
+      {'git': 42},
+      r'''
+line 5, column 11: Unsupported value for "git". Must be a String or a Map.

 5 │      "git": 42
   │ ┌───────────^
 6 │ │   }
   │ └──^
-  ╵''');
+  ╵''',
+    );
   });
 
   test('git - empty map', () {
@@ -287,29 +313,33 @@
   });
 
   test('git - null url', () {
-    _expectThrows({
-      'git': {'url': null}
-    }, r'''
-line 6, column 12: These keys had `null` values, which is not allowed: [url]
+    _expectThrows(
+      {
+        'git': {'url': null}
+      },
+      r'''
+line 6, column 5: These keys had `null` values, which is not allowed: [url]

-6 │       "url": null
-  │ ┌────────────^
-7 │ │    }
-  │ └───^
-  ╵''');
+6 │     "url": null
+  │     ^^^^^
+  ╵''',
+    );
   });
 
   test('git - int url', () {
-    _expectThrows({
-      'git': {'url': 42}
-    }, r'''
-line 6, column 12: Unsupported value for `url`.
+    _expectThrows(
+      {
+        'git': {'url': 42}
+      },
+      r'''
+line 6, column 12: Unsupported value for "url".

 6 │       "url": 42
   │ ┌────────────^
 7 │ │    }
   │ └───^
-  ╵''');
+  ╵''',
+    );
   });
 }
 
@@ -337,25 +367,31 @@
   });
 
   test('null content', () {
-    _expectThrows({'path': null}, r'''
-line 5, column 12: Must be a String.
+    _expectThrows(
+      {'path': null},
+      r'''
+line 5, column 12: Unsupported value for "path". Must be a String.

 5 │      "path": null
   │ ┌────────────^
 6 │ │   }
   │ └──^
-  ╵''');
+  ╵''',
+    );
   });
 
   test('int content', () {
-    _expectThrows({'path': 42}, r'''
-line 5, column 12: Must be a String.
+    _expectThrows(
+      {'path': 42},
+      r'''
+line 5, column 12: Unsupported value for "path". Must be a String.

 5 │      "path": 42
   │ ┌────────────^
 6 │ │   }
   │ └──^
-  ╵''');
+  ╵''',
+    );
   });
 }
 
diff --git a/pkgs/pubspec_parse/test/parse_test.dart b/pkgs/pubspec_parse/test/parse_test.dart
index 3c79d87..ca822e7 100644
--- a/pkgs/pubspec_parse/test/parse_test.dart
+++ b/pkgs/pubspec_parse/test/parse_test.dart
@@ -75,29 +75,29 @@
   group('publish_to', () {
     for (var entry in {
       42: r'''
-line 3, column 16: Unsupported value for `publish_to`.
+line 3, column 16: Unsupported value for "publish_to".

 3 │  "publish_to": 42
   │                ^^
   ╵''',
       '##not a uri!': r'''
-line 3, column 16: must be an http or https URL.
+line 3, column 16: Unsupported value for "publish_to". Must be an http or https URL.

 3 │  "publish_to": "##not a uri!"
   │                ^^^^^^^^^^^^^^
   ╵''',
       '/cool/beans': r'''
-line 3, column 16: must be an http or https URL.
+line 3, column 16: Unsupported value for "publish_to". Must be an http or https URL.

 3 │  "publish_to": "/cool/beans"
   │                ^^^^^^^^^^^^^
   ╵''',
       'file:///Users/kevmoo/': r'''
-line 3, column 16: must be an http or https URL.
+line 3, column 16: Unsupported value for "publish_to". Must be an http or https URL.

 3 │  "publish_to": "file:///Users/kevmoo/"
   │                ^^^^^^^^^^^^^^^^^^^^^^^
-  ╵'''
+  ╵''',
     }.entries) {
       test('cannot be `${entry.key}`', () {
         expectParseThrows(
@@ -182,14 +182,30 @@
 
   group('invalid', () {
     test('null', () {
-      expect(() => parse(null), throwsArgumentError);
+      expectParseThrows(
+        null,
+        r'''
+line 1, column 1: Not a map
+  ╷
+1 │ null
+  │ ^^^^
+  ╵''',
+      );
     });
     test('empty string', () {
-      expect(() => parse(''), throwsArgumentError);
+      expectParseThrows(
+        '',
+        r'''
+line 1, column 1: Not a map
+  ╷
+1 │ ""
+  │ ^^
+  ╵''',
+      );
     });
     test('array', () {
       expectParseThrows([], r'''
-line 1, column 1: Does not represent a YAML map.
+line 1, column 1: Not a map

 1 │ []
   │ ^^
@@ -210,7 +226,7 @@
         'name': 'sample',
         'environment': {'dart': 'cool'}
       }, r'''
-line 4, column 3: Unrecognized keys: [dart]; supported keys: [sdk]
+line 4, column 3: Use "sdk" to for Dart SDK constraints.

 4 │   "dart": "cool"
   │   ^^^^^^
@@ -218,26 +234,32 @@
     });
 
     test('environment values cannot be int', () {
-      expectParseThrows({
-        'name': 'sample',
-        'environment': {'sdk': 42}
-      }, r'''
-line 4, column 10: `42` is not a String.
+      expectParseThrows(
+        {
+          'name': 'sample',
+          'environment': {'sdk': 42}
+        },
+        r'''
+line 4, column 10: Unsupported value for "sdk". `42` is not a String.

 4 │     "sdk": 42
   │ ┌──────────^
 5 │ │  }
   │ └─^
-  ╵''');
+  ╵''',
+      );
     });
 
     test('version', () {
-      expectParseThrows({'name': 'sample', 'version': 'invalid'}, r'''
-line 3, column 13: Could not parse "invalid".
+      expectParseThrows(
+        {'name': 'sample', 'version': 'invalid'},
+        r'''
+line 3, column 13: Unsupported value for "version". Could not parse "invalid".

 3 │  "version": "invalid"
   │             ^^^^^^^^^
-  ╵''');
+  ╵''',
+      );
     });
 
     test('invalid environment value', () {
@@ -245,7 +267,7 @@
         'name': 'sample',
         'environment': {'sdk': 'silly'}
       }, r'''
-line 4, column 10: Could not parse version "silly". Unknown text at "silly".
+line 4, column 10: Unsupported value for "sdk". Could not parse version "silly". Unknown text at "silly".

 4 │   "sdk": "silly"
   │          ^^^^^^^
@@ -253,45 +275,80 @@
     });
 
     test('bad repository url', () {
-      expectParseThrows({
-        'name': 'foo',
-        'repository': {'x': 'y'},
-      }, r'''
-line 3, column 16: Unsupported value for `repository`.
+      expectParseThrows(
+        {
+          'name': 'foo',
+          'repository': {'x': 'y'},
+        },
+        r'''
+line 3, column 16: Unsupported value for "repository".

 3 │    "repository": {
   │ ┌────────────────^
 4 │ │   "x": "y"
 5 │ └  }
-  ╵''', skipTryPub: true);
+  ╵''',
+        skipTryPub: true,
+      );
     });
 
     test('bad issue_tracker url', () {
-      expectParseThrows({
-        'name': 'foo',
-        'issue_tracker': {'x': 'y'},
-      }, r'''
-line 3, column 19: Unsupported value for `issue_tracker`.
+      expectParseThrows(
+        {
+          'name': 'foo',
+          'issue_tracker': {'x': 'y'},
+        },
+        r'''
+line 3, column 19: Unsupported value for "issue_tracker".

 3 │    "issue_tracker": {
   │ ┌───────────────────^
 4 │ │   "x": "y"
 5 │ └  }
-  ╵''', skipTryPub: true);
+  ╵''',
+        skipTryPub: true,
+      );
     });
   });
 
   group('lenient', () {
     test('null', () {
-      expect(() => parse(null, lenient: true), throwsArgumentError);
+      expectParseThrows(
+        null,
+        r'''
+line 1, column 1: Not a map
+  ╷
+1 │ null
+  │ ^^^^
+  ╵''',
+        lenient: true,
+      );
     });
 
     test('empty string', () {
-      expect(() => parse('', lenient: true), throwsArgumentError);
+      expectParseThrows(
+        '',
+        r'''
+line 1, column 1: Not a map
+  ╷
+1 │ ""
+  │ ^^
+  ╵''',
+        lenient: true,
+      );
     });
 
     test('name cannot be empty', () {
-      expect(() => parse({}, lenient: true), throwsException);
+      expectParseThrows(
+        {},
+        r'''
+line 1, column 1: "name" cannot be empty.
+  ╷
+1 │ {}
+  │ ^^
+  ╵''',
+        lenient: true,
+      );
     });
 
     test('bad repository url', () {
diff --git a/pkgs/pubspec_parse/test/test_utils.dart b/pkgs/pubspec_parse/test/test_utils.dart
index 7f8ae87..b61cdbd 100644
--- a/pkgs/pubspec_parse/test/test_utils.dart
+++ b/pkgs/pubspec_parse/test/test_utils.dart
@@ -5,6 +5,7 @@
 import 'dart:cli';
 import 'dart:convert';
 
+import 'package:checked_yaml/checked_yaml.dart';
 import 'package:json_annotation/json_annotation.dart';
 import 'package:pubspec_parse/pubspec_parse.dart';
 import 'package:stack_trace/stack_trace.dart';
@@ -25,10 +26,11 @@
 
 void _printDebugParsedYamlException(ParsedYamlException e) {
   var innerError = e.innerError;
-  var innerStack = e.innerStack;
+  StackTrace innerStack;
 
-  if (e.innerError is CheckedFromJsonException) {
-    final cfje = e.innerError as CheckedFromJsonException;
+  if (innerError is CheckedFromJsonException) {
+    final cfje = innerError as CheckedFromJsonException;
+
     if (cfje.innerError != null) {
       innerError = cfje.innerError;
       innerStack = cfje.innerStack;
@@ -98,6 +100,14 @@
   Object content,
   String expectedError, {
   bool skipTryPub = false,
+  bool lenient = false,
 }) =>
-    expect(() => parse(content, quietOnError: true, skipTryPub: skipTryPub),
-        _throwsParsedYamlException(expectedError));
+    expect(
+      () => parse(
+            content,
+            lenient: lenient,
+            quietOnError: true,
+            skipTryPub: skipTryPub,
+          ),
+      _throwsParsedYamlException(expectedError),
+    );