Merge remote-tracking branch 'weave/master' into 'weave/dev'

ec47eb0 examples/provider/wifi_manager: find iface name
43bf6b7 Update gtest
e03c094 Include of gtest_prod.h only building unittests
0dbbf60 AddTo will return AddToTypeProxy for convenience
48a8669 Remove domain from weave::Error
50a147a Enforce printf format literals checking
diff --git a/Makefile b/Makefile
index 512c2a6..de69f40 100644
--- a/Makefile
+++ b/Makefile
@@ -26,9 +26,9 @@
 	-Wall \
 	-Werror \
 	-Wextra \
+	-Wformat=2 \
 	-Wl,--exclude-libs,ALL \
 	-Wno-char-subscripts \
-	-Wno-format-nonliteral \
 	-Wno-missing-field-initializers \
 	-Wno-unused-local-typedefs \
 	-Wno-unused-parameter \
@@ -71,6 +71,10 @@
 OBJFILES = $(shell find out/$(BUILD_MODE)/ -type f -name '*.o')
 -include $(OBJFILES:.o=.d)
 
+DEFS_TEST := \
+	$(DEFS_$(BUILD_MODE)) \
+	-DHAS_GTEST=1
+
 ###
 # libweave.so
 
@@ -85,7 +89,7 @@
 weave_obj_files := $(WEAVE_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
 
 # TODO(jacobmarble): There are too many gtest/gmock deps in non-test targets. Fix.
-$(weave_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/gtest/gtest.h
+$(weave_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
@@ -93,7 +97,7 @@
 	rm -f $@
 	$(AR) crsT $@ $^
 
-all : out/$(BUILD_MODE)/libweave.so out/$(BUILD_MODE)/libweave_exports_testrunner out/$(BUILD_MODE)/libweave_testrunner all-examples
+all : out/$(BUILD_MODE)/libweave.so all-examples out/$(BUILD_MODE)/libweave_exports_testrunner out/$(BUILD_MODE)/libweave_testrunner
 
 clean :
 	rm -rf out
diff --git a/examples/daemon/ledflasher/ledflasher.cc b/examples/daemon/ledflasher/ledflasher.cc
index 2e38d95..369b003 100644
--- a/examples/daemon/ledflasher/ledflasher.cc
+++ b/examples/daemon/ledflasher/ledflasher.cc
@@ -102,7 +102,7 @@
       return;
     }
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
@@ -124,7 +124,7 @@
       return;
     }
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
diff --git a/examples/daemon/light/light.cc b/examples/daemon/light/light.cc
index 298fcaf..a78231f 100644
--- a/examples/daemon/light/light.cc
+++ b/examples/daemon/light/light.cc
@@ -215,7 +215,7 @@
       return;
     }
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
@@ -241,7 +241,7 @@
       return;
     }
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
@@ -275,7 +275,7 @@
     }
 
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
diff --git a/examples/daemon/lock/lock.cc b/examples/daemon/lock/lock.cc
index 0785c14..fcc6ad7 100644
--- a/examples/daemon/lock/lock.cc
+++ b/examples/daemon/lock/lock.cc
@@ -98,8 +98,8 @@
       if (!weave::StringToEnum(requested_state, &new_lock_status)) {
         // Invalid lock state was specified.
         weave::ErrorPtr error;
-        weave::Error::AddTo(&error, FROM_HERE, "example",
-                            "invalid_parameter_value", "Invalid parameters");
+        weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
+                            "Invalid parameters");
         cmd->Abort(error.get(), nullptr);
         return;
       }
@@ -114,7 +114,7 @@
       return;
     }
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
diff --git a/examples/daemon/oven/oven.cc b/examples/daemon/oven/oven.cc
index ff1c60b..daf1971 100644
--- a/examples/daemon/oven/oven.cc
+++ b/examples/daemon/oven/oven.cc
@@ -191,7 +191,7 @@
     }
 
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
@@ -215,7 +215,7 @@
     }
 
     weave::ErrorPtr error;
-    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
+    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
                         "Invalid parameters");
     cmd->Abort(error.get(), nullptr);
   }
diff --git a/examples/daemon/sample/sample.cc b/examples/daemon/sample/sample.cc
index f4ad3d9..7e58193 100644
--- a/examples/daemon/sample/sample.cc
+++ b/examples/daemon/sample/sample.cc
@@ -88,8 +88,8 @@
     std::string name;
     if (!params.GetString("name", &name)) {
       weave::ErrorPtr error;
-      weave::Error::AddTo(&error, FROM_HERE, "example",
-                          "invalid_parameter_value", "Name is missing");
+      weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
+                          "Name is missing");
       cmd->Abort(error.get(), nullptr);
       return;
     }
diff --git a/examples/provider/curl_http_client.cc b/examples/provider/curl_http_client.cc
index de8b3dd..2b1fac3 100644
--- a/examples/provider/curl_http_client.cc
+++ b/examples/provider/curl_http_client.cc
@@ -109,7 +109,7 @@
 
   ErrorPtr error;
   if (res != CURLE_OK) {
-    Error::AddTo(&error, FROM_HERE, "curl", "curl_easy_perform_error",
+    Error::AddTo(&error, FROM_HERE, "curl_easy_perform_error",
                  curl_easy_strerror(res));
     return {nullptr, std::move(error)};
   }
diff --git a/examples/provider/event_http_client.cc b/examples/provider/event_http_client.cc
index fbfc6d8..0346a67 100644
--- a/examples/provider/event_http_client.cc
+++ b/examples/provider/event_http_client.cc
@@ -60,7 +60,7 @@
   if (!req) {
     ErrorPtr error;
     auto err = EVUTIL_SOCKET_ERROR();
-    Error::AddToPrintf(&error, FROM_HERE, "http_client", "request_failed",
+    Error::AddToPrintf(&error, FROM_HERE, "request_failed",
                        "request failed: %s",
                        evutil_socket_error_to_string(err));
     state->task_runner_->PostDelayedTask(
@@ -134,7 +134,7 @@
   if (res >= 0)
     return;
   ErrorPtr error;
-  Error::AddToPrintf(&error, FROM_HERE, "http_client", "request_failed",
+  Error::AddToPrintf(&error, FROM_HERE, "request_failed",
                      "request failed: %s %s", EnumToString(method).c_str(),
                      url.c_str());
   task_runner_->PostDelayedTask(
diff --git a/examples/provider/ssl_stream.cc b/examples/provider/ssl_stream.cc
index eea28c0..8c1a756 100644
--- a/examples/provider/ssl_stream.cc
+++ b/examples/provider/ssl_stream.cc
@@ -21,7 +21,7 @@
                  unsigned long ssl_error_code) {
   ERR_load_BIO_strings();
   SSL_load_error_strings();
-  Error::AddToPrintf(error, location, "ssl_stream", error_code, "%s: %s",
+  Error::AddToPrintf(error, location, error_code, "%s: %s",
                      ERR_lib_error_string(ssl_error_code),
                      ERR_reason_error_string(ssl_error_code));
 }
diff --git a/examples/provider/wifi_manager.cc b/examples/provider/wifi_manager.cc
index ed6a9fd..7597e47 100644
--- a/examples/provider/wifi_manager.cc
+++ b/examples/provider/wifi_manager.cc
@@ -5,6 +5,7 @@
 #include "examples/provider/wifi_manager.h"
 
 #include <arpa/inet.h>
+#include <dirent.h>
 #include <linux/wireless.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
@@ -32,18 +33,43 @@
   for (auto& i : args)
     args_vector.push_back(i.c_str());
   args_vector.push_back(nullptr);
-
   execvp(path.c_str(), const_cast<char**>(args_vector.data()));
   NOTREACHED();
   return 0;
 }
 
+int ForkCmdAndWait(const std::string& path,
+                   const std::vector<std::string>& args) {
+  int pid = ForkCmd(path, args);
+  int status = 0;
+  CHECK_EQ(pid, waitpid(pid, &status, 0));
+  return status;
+}
+
+std::string FindWirelessInterface() {
+  std::string sysfs_net{"/sys/class/net"};
+  DIR* net_dir = opendir(sysfs_net.c_str());
+  dirent* iface;
+  while ((iface = readdir(net_dir))) {
+    auto path = sysfs_net + "/" + iface->d_name + "/wireless";
+    DIR* wireless_dir = opendir(path.c_str());
+    if (wireless_dir != nullptr) {
+      closedir(net_dir);
+      closedir(wireless_dir);
+      return iface->d_name;
+    }
+  }
+  closedir(net_dir);
+  return "";
+}
+
 }  // namespace
 
 WifiImpl::WifiImpl(provider::TaskRunner* task_runner, EventNetworkImpl* network)
-    : task_runner_{task_runner}, network_{network} {
+  : task_runner_{task_runner}, network_{network}, iface_{FindWirelessInterface()} {
+  CHECK(!iface_.empty()) <<  "WiFi interface not found";
   CHECK_EQ(0u, getuid())
-      << "WiFi manager expects root access to control WiFi capabilities";
+      << "\nWiFi manager expects root access to control WiFi capabilities";
   StopAccessPoint();
 }
 WifiImpl::~WifiImpl() {
@@ -62,7 +88,7 @@
       CHECK_GE(sockf_d, 0) << strerror(errno);
 
       iwreq wreq = {};
-      snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "wlan0");
+      strncpy(wreq.ifr_name, iface_.c_str(), sizeof(wreq.ifr_name));
       std::string essid(' ', IW_ESSID_MAX_SIZE + 1);
       wreq.u.essid.pointer = &essid[0];
       wreq.u.essid.length = essid.size();
@@ -84,7 +110,7 @@
 
   if (base::Time::Now() >= until) {
     ErrorPtr error;
-    Error::AddTo(&error, FROM_HERE, "wifi", "timeout",
+    Error::AddTo(&error, FROM_HERE, "timeout",
                  "Timeout connecting to WiFI network.");
     task_runner_->PostDelayedTask(
         FROM_HERE, base::Bind(callback, base::Passed(&error)), {});
@@ -105,7 +131,7 @@
   CHECK(!hostapd_started_);
   if (hostapd_started_) {
     ErrorPtr error;
-    Error::AddTo(&error, FROM_HERE, "wifi", "busy", "Running Access Point.");
+    Error::AddTo(&error, FROM_HERE, "busy", "Running Access Point.");
     task_runner_->PostDelayedTask(
         FROM_HERE, base::Bind(callback, base::Passed(&error)), {});
     return;
@@ -119,24 +145,24 @@
   if (hostapd_started_)
     return;
 
-  // Release wlan0 interface.
-  CHECK_EQ(0, std::system("nmcli nm wifi off"));
-  CHECK_EQ(0, std::system("rfkill unblock wlan"));
+  // Release wifi interface.
+  CHECK_EQ(0, ForkCmdAndWait("nmcli", {"nm", "wifi",  "off"}));
+  CHECK_EQ(0, ForkCmdAndWait("rfkill", {"unblock", "wlan"}));
   sleep(1);
 
   std::string hostapd_conf = "/tmp/weave_hostapd.conf";
   {
     std::ofstream ofs(hostapd_conf);
-    ofs << "interface=wlan0" << std::endl;
+    ofs << "interface=" << iface_ << std::endl;
     ofs << "channel=1" << std::endl;
     ofs << "ssid=" << ssid << std::endl;
   }
 
-  CHECK_EQ(0, std::system(("hostapd -B -K " + hostapd_conf).c_str()));
+  CHECK_EQ(0, ForkCmdAndWait("hostapd", {"-B", "-K", hostapd_conf}));
   hostapd_started_ = true;
 
   for (size_t i = 0; i < 10; ++i) {
-    if (0 == std::system("ifconfig wlan0 192.168.76.1/24"))
+    if (0 == ForkCmdAndWait("ifconfig", {iface_, "192.168.76.1/24"}))
       break;
     sleep(1);
   }
@@ -148,22 +174,22 @@
     ofs << "bind-interfaces" << std::endl;
     ofs << "log-dhcp" << std::endl;
     ofs << "dhcp-range=192.168.76.10,192.168.76.100" << std::endl;
-    ofs << "interface=wlan0" << std::endl;
+    ofs << "interface=" << iface_ << std::endl;
     ofs << "dhcp-leasefile=" << dnsmasq_conf << ".leases" << std::endl;
   }
 
-  CHECK_EQ(0, std::system(("dnsmasq --conf-file=" + dnsmasq_conf).c_str()));
+  CHECK_EQ(0, ForkCmdAndWait("dnsmasq", {"--conf-file=" + dnsmasq_conf}));
 }
 
 void WifiImpl::StopAccessPoint() {
-  base::IgnoreResult(std::system("pkill -f dnsmasq.*/tmp/weave"));
-  base::IgnoreResult(std::system("pkill -f hostapd.*/tmp/weave"));
-  CHECK_EQ(0, std::system("nmcli nm wifi on"));
+  base::IgnoreResult(ForkCmdAndWait("pkill", {"-f", "dnsmasq.*/tmp/weave"}));
+  base::IgnoreResult(ForkCmdAndWait("pkill", {"-f", "hostapd.*/tmp/weave"}));
+  CHECK_EQ(0, ForkCmdAndWait("nmcli", {"nm", "wifi", "on"}));
   hostapd_started_ = false;
 }
 
 bool WifiImpl::HasWifiCapability() {
-  return std::system("nmcli dev | grep ^wlan0") == 0;
+  return !FindWirelessInterface().empty();
 }
 
 }  // namespace examples
diff --git a/examples/provider/wifi_manager.h b/examples/provider/wifi_manager.h
index c043523..2bfc5ca 100644
--- a/examples/provider/wifi_manager.h
+++ b/examples/provider/wifi_manager.h
@@ -48,6 +48,7 @@
   provider::TaskRunner* task_runner_{nullptr};
   EventNetworkImpl* network_{nullptr};
   base::WeakPtrFactory<WifiImpl> weak_ptr_factory_{this};
+  std::string iface_;
 };
 
 }  // namespace examples
diff --git a/include/weave/error.h b/include/weave/error.h
index 14a85be..0cf8dc5 100644
--- a/include/weave/error.h
+++ b/include/weave/error.h
@@ -24,38 +24,48 @@
  public:
   ~Error() = default;
 
+  class AddToTypeProxy {
+   public:
+    operator bool() const { return false; }
+
+    template <class T>
+    operator std::unique_ptr<T>() const {
+      return nullptr;
+    }
+
+    template <class T>
+    operator T*() const {
+      return nullptr;
+    }
+  };
+
   // Creates an instance of Error class.
   static ErrorPtr Create(const tracked_objects::Location& location,
-                         const std::string& domain,
                          const std::string& code,
                          const std::string& message);
   static ErrorPtr Create(const tracked_objects::Location& location,
-                         const std::string& domain,
                          const std::string& code,
                          const std::string& message,
                          ErrorPtr inner_error);
   // If |error| is not nullptr, creates another instance of Error class,
   // initializes it with specified arguments and adds it to the head of
   // the error chain pointed to by |error|.
-  static void AddTo(ErrorPtr* error,
-                    const tracked_objects::Location& location,
-                    const std::string& domain,
-                    const std::string& code,
-                    const std::string& message);
+  static AddToTypeProxy AddTo(ErrorPtr* error,
+                              const tracked_objects::Location& location,
+                              const std::string& code,
+                              const std::string& message);
   // Same as the Error::AddTo above, but allows to pass in a printf-like
   // format string and optional parameters to format the error message.
-  static void AddToPrintf(ErrorPtr* error,
-                          const tracked_objects::Location& location,
-                          const std::string& domain,
-                          const std::string& code,
-                          const char* format,
-                          ...) PRINTF_FORMAT(5, 6);
+  static AddToTypeProxy AddToPrintf(ErrorPtr* error,
+                                    const tracked_objects::Location& location,
+                                    const std::string& code,
+                                    const char* format,
+                                    ...) PRINTF_FORMAT(4, 5);
 
   // Clones error with all inner errors.
   ErrorPtr Clone() const;
 
-  // Returns the error domain, code and message
-  const std::string& GetDomain() const { return domain_; }
+  // Returns the error code and message
   const std::string& GetCode() const { return code_; }
   const std::string& GetMessage() const { return message_; }
 
@@ -64,13 +74,9 @@
     return location_;
   }
 
-  // Checks if this or any of the inner errors in the chain has the specified
-  // error domain.
-  bool HasDomain(const std::string& domain) const;
-
   // Checks if this or any of the inner errors in the chain matches the
-  // specified error domain and code.
-  bool HasError(const std::string& domain, const std::string& code) const;
+  // specified error code.
+  bool HasError(const std::string& code) const;
 
   // Gets a pointer to the inner error, if present. Returns nullptr otherwise.
   const Error* GetInnerError() const { return inner_error_.get(); }
@@ -79,41 +85,27 @@
   // Returns itself if no inner error are available.
   const Error* GetFirstError() const;
 
-  // Finds an error object of particular domain in the error chain stating at
-  // |error_chain_start|. Returns the a pointer to the first matching error
-  // object found.
-  // Returns nullptr if no match is found.
-  // This method is safe to call on a nullptr |error_chain_start| in which case
-  // the result will also be nullptr.
-  static const Error* FindErrorOfDomain(const Error* error_chain_start,
-                                        const std::string& domain);
-  // Finds an error of particular domain with the given code in the error chain
-  // stating at |error_chain_start|. Returns the pointer to the first matching
-  // error object.
+  // Finds an error with the given code in the error chain stating at
+  // |error_chain_start|. Returns the pointer to the first matching error
+  // object.
   // Returns nullptr if no match is found or if |error_chain_start| is nullptr.
   static const Error* FindError(const Error* error_chain_start,
-                                const std::string& domain,
                                 const std::string& code);
 
  protected:
   // Constructor is protected since this object is supposed to be
   // created via the Create factory methods.
   Error(const tracked_objects::Location& location,
-        const std::string& domain,
         const std::string& code,
         const std::string& message,
         ErrorPtr inner_error);
 
   Error(const tracked_objects::LocationSnapshot& location,
-        const std::string& domain,
         const std::string& code,
         const std::string& message,
         ErrorPtr inner_error);
 
-  // Error domain. The domain defines the scopes for error codes.
-  // Two errors with the same code but different domains are different errors.
-  std::string domain_;
-  // Error code. A unique error code identifier within the given domain.
+  // Error code. A unique error code identifier.
   std::string code_;
   // Human-readable error message.
   std::string message_;
diff --git a/src/base_api_handler.cc b/src/base_api_handler.cc
index 5562b6c..312e20b 100644
--- a/src/base_api_handler.cc
+++ b/src/base_api_handler.cc
@@ -143,8 +143,7 @@
   AuthScope auth_scope{AuthScope::kNone};
   if (!StringToEnum(anonymous_access_role, &auth_scope)) {
     ErrorPtr error;
-    Error::AddToPrintf(&error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kInvalidPropValue,
+    Error::AddToPrintf(&error, FROM_HERE, errors::commands::kInvalidPropValue,
                        "Invalid localAnonymousAccessMaxRole value '%s'",
                        anonymous_access_role.c_str());
     command->Abort(error.get(), nullptr);
diff --git a/src/commands/cloud_command_proxy_unittest.cc b/src/commands/cloud_command_proxy_unittest.cc
index 0e998ef..013769d 100644
--- a/src/commands/cloud_command_proxy_unittest.cc
+++ b/src/commands/cloud_command_proxy_unittest.cc
@@ -192,7 +192,7 @@
       *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
   task_runner_.Run();
   ErrorPtr error;
-  Error::AddTo(&error, FROM_HERE, "TEST", "TEST", "TEST");
+  Error::AddTo(&error, FROM_HERE, "TEST", "TEST");
   callback.Run(error->Clone());
   task_runner_.Run();
   EXPECT_GE(task_runner_.GetClock()->Now() - started,
diff --git a/src/commands/command_instance.cc b/src/commands/command_instance.cc
index da62887..fc9b0e7 100644
--- a/src/commands/command_instance.cc
+++ b/src/commands/command_instance.cc
@@ -37,11 +37,10 @@
 bool ReportInvalidStateTransition(ErrorPtr* error,
                                   Command::State from,
                                   Command::State to) {
-  Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                     errors::commands::kInvalidState,
-                     "State switch impossible: '%s' -> '%s'",
-                     EnumToString(from).c_str(), EnumToString(to).c_str());
-  return false;
+  return Error::AddToPrintf(error, FROM_HERE, errors::commands::kInvalidState,
+                            "State switch impossible: '%s' -> '%s'",
+                            EnumToString(from).c_str(),
+                            EnumToString(to).c_str());
 }
 
 }  // namespace
@@ -153,11 +152,9 @@
     // Make sure the "parameters" property is actually an object.
     const base::DictionaryValue* params_dict = nullptr;
     if (!params_value->GetAsDictionary(&params_dict)) {
-      Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
-                         errors::json::kObjectExpected,
-                         "Property '%s' must be a JSON object",
-                         commands::attributes::kCommand_Parameters);
-      return params;
+      return Error::AddToPrintf(error, FROM_HERE, errors::json::kObjectExpected,
+                                "Property '%s' must be a JSON object",
+                                commands::attributes::kCommand_Parameters);
     }
     params.reset(params_dict->DeepCopy());
   } else {
@@ -182,11 +179,9 @@
   // Get the command JSON object from the value.
   const base::DictionaryValue* json = nullptr;
   if (!value->GetAsDictionary(&json)) {
-    Error::AddTo(error, FROM_HERE, errors::json::kDomain,
-                 errors::json::kObjectExpected,
-                 "Command instance is not a JSON object");
     command_id->clear();
-    return instance;
+    return Error::AddTo(error, FROM_HERE, errors::json::kObjectExpected,
+                        "Command instance is not a JSON object");
   }
 
   // Get the command ID from 'id' property.
@@ -196,17 +191,15 @@
   // Get the command name from 'name' property.
   std::string command_name;
   if (!json->GetString(commands::attributes::kCommand_Name, &command_name)) {
-    Error::AddTo(error, FROM_HERE, errors::commands::kDomain,
-                 errors::commands::kPropertyMissing, "Command name is missing");
-    return instance;
+    return Error::AddTo(error, FROM_HERE, errors::commands::kPropertyMissing,
+                        "Command name is missing");
   }
 
   auto parameters = GetCommandParameters(json, error);
   if (!parameters) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kCommandFailed,
-                       "Failed to validate command '%s'", command_name.c_str());
-    return instance;
+    return Error::AddToPrintf(
+        error, FROM_HERE, errors::commands::kCommandFailed,
+        "Failed to validate command '%s'", command_name.c_str());
   }
 
   instance.reset(new CommandInstance{command_name, origin, *parameters});
diff --git a/src/commands/command_instance_unittest.cc b/src/commands/command_instance_unittest.cc
index 8d70b8b..803d5b4 100644
--- a/src/commands/command_instance_unittest.cc
+++ b/src/commands/command_instance_unittest.cc
@@ -143,7 +143,7 @@
   instance->SetID("testId");
 
   ErrorPtr error;
-  Error::AddTo(&error, FROM_HERE, "DOMAIN", "CODE", "MESSAGE");
+  Error::AddTo(&error, FROM_HERE, "CODE", "MESSAGE");
   instance->Abort(error.get(), nullptr);
 
   json->MergeDictionary(CreateDictionaryValue(R"({
diff --git a/src/commands/schema_constants.cc b/src/commands/schema_constants.cc
index 34d6db8..732cf44 100644
--- a/src/commands/schema_constants.cc
+++ b/src/commands/schema_constants.cc
@@ -8,7 +8,6 @@
 
 namespace errors {
 namespace commands {
-const char kDomain[] = "command_schema";
 
 const char kTypeMismatch[] = "type_mismatch";
 const char kInvalidPropValue[] = "invalid_parameter_value";
diff --git a/src/commands/schema_constants.h b/src/commands/schema_constants.h
index 9199480..360079a 100644
--- a/src/commands/schema_constants.h
+++ b/src/commands/schema_constants.h
@@ -9,8 +9,6 @@
 
 namespace errors {
 namespace commands {
-// Error domain for command schema description.
-extern const char kDomain[];
 
 // Common command definition error codes.
 extern const char kTypeMismatch[];
diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc
index 3f6ebf9..550775d 100644
--- a/src/component_manager_impl.cc
+++ b/src/component_manager_impl.cc
@@ -47,20 +47,17 @@
       return false;
   }
   if (root->GetWithoutPathExpansion(name, nullptr)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kInvalidState,
-                       "Component '%s' already exists at path '%s'",
-                       name.c_str(), path.c_str());
-    return false;
+    return Error::AddToPrintf(error, FROM_HERE, errors::commands::kInvalidState,
+                              "Component '%s' already exists at path '%s'",
+                              name.c_str(), path.c_str());
   }
 
   // Check to make sure the declared traits are already defined.
   for (const std::string& trait : traits) {
     if (!FindTraitDefinition(trait)) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kInvalidPropValue,
-                         "Trait '%s' is undefined", trait.c_str());
-      return false;
+      return Error::AddToPrintf(error, FROM_HERE,
+                                errors::commands::kInvalidPropValue,
+                                "Trait '%s' is undefined", trait.c_str());
     }
   }
   std::unique_ptr<base::DictionaryValue> dict{new base::DictionaryValue};
@@ -110,11 +107,9 @@
   }
 
   if (!root->RemoveWithoutPathExpansion(name, nullptr)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kInvalidState,
-                       "Component '%s' does not exist at path '%s'",
-                       name.c_str(), path.c_str());
-    return false;
+    return Error::AddToPrintf(error, FROM_HERE, errors::commands::kInvalidState,
+                              "Component '%s' does not exist at path '%s'",
+                              name.c_str(), path.c_str());
   }
 
   for (const auto& cb : on_componet_tree_changed_)
@@ -135,20 +130,17 @@
 
   base::ListValue* array_value = nullptr;
   if (!root->GetListWithoutPathExpansion(name, &array_value)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kInvalidState,
-                       "There is no component array named '%s' at path '%s'",
-                       name.c_str(), path.c_str());
-    return false;
+    return Error::AddToPrintf(
+        error, FROM_HERE, errors::commands::kInvalidState,
+        "There is no component array named '%s' at path '%s'", name.c_str(),
+        path.c_str());
   }
 
   if (!array_value->Remove(index, nullptr)) {
-    Error::AddToPrintf(
-        error, FROM_HERE, errors::commands::kDomain,
-        errors::commands::kInvalidState,
+    return Error::AddToPrintf(
+        error, FROM_HERE, errors::commands::kInvalidState,
         "Component array '%s' at path '%s' does not have an element %zu",
         name.c_str(), path.c_str(), index);
-    return false;
   }
 
   for (const auto& cb : on_componet_tree_changed_)
@@ -170,8 +162,7 @@
   // definition is exactly the same, or else this is an error.
   for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
     if (it.value().GetType() != base::Value::TYPE_DICTIONARY) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kTypeMismatch,
+      Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch,
                          "Trait '%s' must be an object", it.key().c_str());
       result = false;
       break;
@@ -179,8 +170,7 @@
     const base::DictionaryValue* existing_def = nullptr;
     if (traits_.GetDictionary(it.key(), &existing_def)) {
       if (!existing_def->Equals(&it.value())) {
-        Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                           errors::commands::kTypeMismatch,
+        Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch,
                            "Trait '%s' cannot be redefined", it.key().c_str());
         result = false;
         break;
@@ -240,11 +230,10 @@
     return nullptr;
 
   if (role < minimal_role) {
-    Error::AddToPrintf(
-        error, FROM_HERE, errors::commands::kDomain, "access_denied",
-        "User role '%s' less than minimal: '%s'", EnumToString(role).c_str(),
-        EnumToString(minimal_role).c_str());
-    return nullptr;
+    return Error::AddToPrintf(error, FROM_HERE, "access_denied",
+                              "User role '%s' less than minimal: '%s'",
+                              EnumToString(role).c_str(),
+                              EnumToString(minimal_role).c_str());
   }
 
   std::string component_path = command_instance->GetComponent();
@@ -255,12 +244,11 @@
         SplitAtFirst(command_instance->GetName(), ".", true).first;
     component_path = FindComponentWithTrait(trait_name);
     if (component_path.empty()) {
-      Error::AddToPrintf(
-          error, FROM_HERE, errors::commands::kDomain, "unrouted_command",
+      return Error::AddToPrintf(
+          error, FROM_HERE, "unrouted_command",
           "Unable route command '%s' because there is no component supporting"
           "trait '%s'",
           command_instance->GetName().c_str(), trait_name.c_str());
-      return nullptr;
     }
     command_instance->SetComponent(component_path);
   }
@@ -286,11 +274,9 @@
   }
 
   if (!trait_supported) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       "trait_not_supported",
-                       "Component '%s' doesn't support trait '%s'",
-                       component_path.c_str(), pair.first.c_str());
-    return nullptr;
+    return Error::AddToPrintf(error, FROM_HERE, "trait_not_supported",
+                              "Component '%s' doesn't support trait '%s'",
+                              component_path.c_str(), pair.first.c_str());
   }
 
   if (command_id.empty()) {
@@ -361,11 +347,9 @@
                                           ErrorPtr* error) const {
   const base::DictionaryValue* command = FindCommandDefinition(command_name);
   if (!command) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kInvalidCommandName,
-                       "Command definition for '%s' not found",
-                       command_name.c_str());
-    return false;
+    return Error::AddToPrintf(
+        error, FROM_HERE, errors::commands::kInvalidCommandName,
+        "Command definition for '%s' not found", command_name.c_str());
   }
   std::string value;
   // The JSON definition has been pre-validated already in LoadCommands, so
@@ -423,25 +407,22 @@
     return nullptr;
   auto pair = SplitAtFirst(name, ".", true);
   if (pair.first.empty()) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kPropertyMissing,
-                       "Empty state package in '%s'", name.c_str());
-    return nullptr;
+    return Error::AddToPrintf(error, FROM_HERE,
+                              errors::commands::kPropertyMissing,
+                              "Empty state package in '%s'", name.c_str());
   }
   if (pair.second.empty()) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kPropertyMissing,
-                       "State property name not specified in '%s'",
-                       name.c_str());
-    return nullptr;
+    return Error::AddToPrintf(
+        error, FROM_HERE, errors::commands::kPropertyMissing,
+        "State property name not specified in '%s'", name.c_str());
   }
   std::string key = base::StringPrintf("state.%s", name.c_str());
   const base::Value* value = nullptr;
   if (!component->Get(key, &value)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kPropertyMissing,
-                       "State property '%s' not found in component '%s'",
-                       name.c_str(), component_path.c_str());
+    return Error::AddToPrintf(error, FROM_HERE,
+                              errors::commands::kPropertyMissing,
+                              "State property '%s' not found in component '%s'",
+                              name.c_str(), component_path.c_str());
   }
   return value;
 }
@@ -453,17 +434,14 @@
   base::DictionaryValue dict;
   auto pair = SplitAtFirst(name, ".", true);
   if (pair.first.empty()) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kPropertyMissing,
-                       "Empty state package in '%s'", name.c_str());
-    return false;
+    return Error::AddToPrintf(error, FROM_HERE,
+                              errors::commands::kPropertyMissing,
+                              "Empty state package in '%s'", name.c_str());
   }
   if (pair.second.empty()) {
-    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                       errors::commands::kPropertyMissing,
-                       "State property name not specified in '%s'",
-                       name.c_str());
-    return false;
+    return Error::AddToPrintf(
+        error, FROM_HERE, errors::commands::kPropertyMissing,
+        "State property name not specified in '%s'", name.c_str());
   }
   dict.Set(name, value.DeepCopy());
   return SetStateProperties(component_path, dict, error);
@@ -532,8 +510,7 @@
   for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
     const base::DictionaryValue* command_dict = nullptr;
     if (!it.value().GetAsDictionary(&command_dict)) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kTypeMismatch,
+      Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch,
                          "Package '%s' must be an object", it.key().c_str());
       result = false;
       continue;
@@ -544,7 +521,7 @@
       std::string key = base::StringPrintf("%s.commands.%s", it.key().c_str(),
                                            it_def.key().c_str());
       if (traits_.GetDictionary(key, nullptr)) {
-        Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
+        Error::AddToPrintf(error, FROM_HERE,
                            errors::commands::kInvalidPropValue,
                            "Redefining command '%s.%s'", it.key().c_str(),
                            it_def.key().c_str());
@@ -571,8 +548,7 @@
   for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
     const base::DictionaryValue* state_dict = nullptr;
     if (!it.value().GetAsDictionary(&state_dict)) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kTypeMismatch,
+      Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch,
                          "Package '%s' must be an object", it.key().c_str());
       result = false;
       continue;
@@ -583,7 +559,7 @@
       std::string key = base::StringPrintf("%s.state.%s", it.key().c_str(),
                                            it_def.key().c_str());
       if (traits_.GetDictionary(key, nullptr)) {
-        Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
+        Error::AddToPrintf(error, FROM_HERE,
                            errors::commands::kInvalidPropValue,
                            "Redefining state property '%s.%s'",
                            it.key().c_str(), it_def.key().c_str());
@@ -689,28 +665,24 @@
     auto element = SplitAtFirst(parts[i], "[", true);
     int array_index = -1;
     if (element.first.empty()) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kPropertyMissing,
-                         "Empty path element at '%s'", root_path.c_str());
-      return nullptr;
+      return Error::AddToPrintf(
+          error, FROM_HERE, errors::commands::kPropertyMissing,
+          "Empty path element at '%s'", root_path.c_str());
     }
     if (!element.second.empty()) {
       if (element.second.back() != ']') {
-        Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                           errors::commands::kPropertyMissing,
-                           "Invalid array element syntax '%s'",
-                           parts[i].c_str());
-        return nullptr;
+        return Error::AddToPrintf(
+            error, FROM_HERE, errors::commands::kPropertyMissing,
+            "Invalid array element syntax '%s'", parts[i].c_str());
       }
       element.second.pop_back();
       std::string index_str;
       base::TrimWhitespaceASCII(element.second, base::TrimPositions::TRIM_ALL,
                                 &index_str);
       if (!base::StringToInt(index_str, &array_index) || array_index < 0) {
-        Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                           errors::commands::kInvalidPropValue,
-                           "Invalid array index '%s'", element.second.c_str());
-        return nullptr;
+        return Error::AddToPrintf(
+            error, FROM_HERE, errors::commands::kInvalidPropValue,
+            "Invalid array index '%s'", element.second.c_str());
       }
     }
 
@@ -719,36 +691,32 @@
       // points to the actual parent component. We need the root to point to
       // the 'components' element containing child sub-components instead.
       if (!root->GetDictionary("components", &root)) {
-        Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                           errors::commands::kPropertyMissing,
-                           "Component '%s' does not exist at '%s'",
-                           element.first.c_str(), root_path.c_str());
-        return nullptr;
+        return Error::AddToPrintf(error, FROM_HERE,
+                                  errors::commands::kPropertyMissing,
+                                  "Component '%s' does not exist at '%s'",
+                                  element.first.c_str(), root_path.c_str());
       }
     }
 
     const base::Value* value = nullptr;
     if (!root->GetWithoutPathExpansion(element.first, &value)) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kPropertyMissing,
+      Error::AddToPrintf(error, FROM_HERE, errors::commands::kPropertyMissing,
                          "Component '%s' does not exist at '%s'",
                          element.first.c_str(), root_path.c_str());
       return nullptr;
     }
 
     if (value->GetType() == base::Value::TYPE_LIST && array_index < 0) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kTypeMismatch,
-                         "Element '%s.%s' is an array", root_path.c_str(),
-                         element.first.c_str());
-      return nullptr;
+      return Error::AddToPrintf(error, FROM_HERE,
+                                errors::commands::kTypeMismatch,
+                                "Element '%s.%s' is an array",
+                                root_path.c_str(), element.first.c_str());
     }
     if (value->GetType() == base::Value::TYPE_DICTIONARY && array_index >= 0) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         errors::commands::kTypeMismatch,
-                         "Element '%s.%s' is not an array", root_path.c_str(),
-                         element.first.c_str());
-      return nullptr;
+      return Error::AddToPrintf(error, FROM_HERE,
+                                errors::commands::kTypeMismatch,
+                                "Element '%s.%s' is not an array",
+                                root_path.c_str(), element.first.c_str());
     }
 
     if (value->GetType() == base::Value::TYPE_DICTIONARY) {
@@ -759,12 +727,10 @@
       const base::Value* component_value = nullptr;
       if (!component_array->Get(array_index, &component_value) ||
           !component_value->GetAsDictionary(&root)) {
-        Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                           errors::commands::kPropertyMissing,
-                           "Element '%s.%s' does not contain item #%d",
-                           root_path.c_str(), element.first.c_str(),
-                           array_index);
-        return nullptr;
+        return Error::AddToPrintf(
+            error, FROM_HERE, errors::commands::kPropertyMissing,
+            "Element '%s.%s' does not contain item #%d", root_path.c_str(),
+            element.first.c_str(), array_index);
       }
     }
     if (!root_path.empty())
diff --git a/src/device_manager.cc b/src/device_manager.cc
index 50818ff..8eed558 100644
--- a/src/device_manager.cc
+++ b/src/device_manager.cc
@@ -218,8 +218,7 @@
     std::string component =
         component_manager_->FindComponentWithTrait(it.key());
     if (component.empty()) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
-                         "unrouted_state",
+      Error::AddToPrintf(error, FROM_HERE, "unrouted_state",
                          "Unable to set property value because there is no "
                          "component supporting "
                          "trait '%s'",
@@ -250,7 +249,7 @@
   std::string component = component_manager_->FindComponentWithTrait(trait);
   if (component.empty()) {
     Error::AddToPrintf(
-        error, FROM_HERE, errors::commands::kDomain, "unrouted_state",
+        error, FROM_HERE, "unrouted_state",
         "Unable set value of state property '%s' because there is no component "
         "supporting trait '%s'",
         name.c_str(), trait.c_str());
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc
index c374527..7c20084 100644
--- a/src/device_registration_info.cc
+++ b/src/device_registration_info.cc
@@ -33,9 +33,6 @@
 
 namespace weave {
 
-const char kErrorDomainOAuth2[] = "oauth2";
-const char kErrorDomainGCD[] = "gcd";
-const char kErrorDomainGCDServer[] = "gcd_server";
 const char kErrorAlreayRegistered[] = "already_registered";
 
 namespace {
@@ -55,8 +52,7 @@
 using provider::HttpClient;
 
 inline void SetUnexpectedError(ErrorPtr* error) {
-  Error::AddTo(error, FROM_HERE, kErrorDomainGCD, "unexpected_response",
-               "Unexpected GCD error");
+  Error::AddTo(error, FROM_HERE, "unexpected_response", "Unexpected GCD error");
 }
 
 void ParseGCDError(const base::DictionaryValue* json, ErrorPtr* error) {
@@ -79,8 +75,7 @@
     std::string error_code, error_message;
     if (error_object->GetString("reason", &error_code) &&
         error_object->GetString("message", &error_message)) {
-      Error::AddTo(error, FROM_HERE, kErrorDomainGCDServer, error_code,
-                   error_message);
+      Error::AddTo(error, FROM_HERE, error_code, error_message);
     } else {
       SetUnexpectedError(error);
     }
@@ -201,10 +196,9 @@
       SplitAtFirst(response.GetContentType(), ";", true).first;
 
   if (content_type != http::kJson && content_type != http::kPlain) {
-    Error::AddTo(
-        error, FROM_HERE, errors::json::kDomain, "non_json_content_type",
+    return Error::AddTo(
+        error, FROM_HERE, "non_json_content_type",
         "Unexpected content type: \'" + response.GetContentType() + "\'");
-    return std::unique_ptr<base::DictionaryValue>();
   }
 
   const std::string& json = response.GetData();
@@ -212,17 +206,16 @@
   auto value = base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC,
                                                     nullptr, &error_message);
   if (!value) {
-    Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
-                       errors::json::kParseError,
+    Error::AddToPrintf(error, FROM_HERE, errors::json::kParseError,
                        "Error '%s' occurred parsing JSON string '%s'",
                        error_message.c_str(), json.c_str());
     return std::unique_ptr<base::DictionaryValue>();
   }
   base::DictionaryValue* dict_value = nullptr;
   if (!value->GetAsDictionary(&dict_value)) {
-    Error::AddToPrintf(
-        error, FROM_HERE, errors::json::kDomain, errors::json::kObjectExpected,
-        "Response is not a valid JSON object: '%s'", json.c_str());
+    Error::AddToPrintf(error, FROM_HERE, errors::json::kObjectExpected,
+                       "Response is not a valid JSON object: '%s'",
+                       json.c_str());
     return std::unique_ptr<base::DictionaryValue>();
   } else {
     // |value| is now owned by |dict_value|, so release the scoped_ptr now.
@@ -334,10 +327,11 @@
 
   VLOG(2) << "Device registration record "
           << ((have_credentials) ? "found" : "not found.");
-  if (!have_credentials)
-    Error::AddTo(error, FROM_HERE, kErrorDomainGCD, "device_not_registered",
-                 "No valid device registration record found");
-  return have_credentials;
+  if (!have_credentials) {
+    return Error::AddTo(error, FROM_HERE, "device_not_registered",
+                        "No valid device registration record found");
+  }
+  return true;
 }
 
 std::unique_ptr<base::DictionaryValue>
@@ -358,9 +352,7 @@
     if (!resp->GetString("error_description", &error_message)) {
       error_message = "Unexpected OAuth error";
     }
-    Error::AddTo(error, FROM_HERE, kErrorDomainOAuth2, error_code,
-                 error_message);
-    return std::unique_ptr<base::DictionaryValue>();
+    return Error::AddTo(error, FROM_HERE, error_code, error_message);
   }
   return resp;
 }
@@ -416,8 +408,8 @@
       !json->GetInteger("expires_in", &expires_in) || access_token_.empty() ||
       expires_in <= 0) {
     LOG(ERROR) << "Access token unavailable.";
-    Error::AddTo(&error, FROM_HERE, kErrorDomainOAuth2,
-                 "unexpected_server_response", "Access token unavailable");
+    Error::AddTo(&error, FROM_HERE, "unexpected_server_response",
+                 "Access token unavailable");
     return callback.Run(std::move(error));
   }
   access_token_expiration_ =
@@ -526,8 +518,7 @@
                                             const DoneCallback& callback) {
   if (HaveRegistrationCredentials()) {
     ErrorPtr error;
-    Error::AddTo(&error, FROM_HERE, errors::kErrorDomain,
-                 kErrorAlreayRegistered,
+    Error::AddTo(&error, FROM_HERE, kErrorAlreayRegistered,
                  "Unable to register already registered device");
     return RegisterDeviceError(callback, std::move(error));
   }
@@ -595,7 +586,7 @@
       !json_resp->GetString("robotAccountAuthorizationCode", &auth_code) ||
       !json_resp->GetDictionary("deviceDraft", &device_draft_response) ||
       !device_draft_response->GetString("id", &cloud_id)) {
-    Error::AddTo(&error, FROM_HERE, kErrorDomainGCD, "unexpected_response",
+    Error::AddTo(&error, FROM_HERE, "unexpected_response",
                  "Device account missing in response");
     return RegisterDeviceError(callback, std::move(error));
   }
@@ -630,7 +621,7 @@
       !json_resp->GetString("refresh_token", &refresh_token) ||
       !json_resp->GetInteger("expires_in", &expires_in) ||
       access_token_.empty() || refresh_token.empty() || expires_in <= 0) {
-    Error::AddTo(&error, FROM_HERE, kErrorDomainGCD, "unexpected_response",
+    Error::AddTo(&error, FROM_HERE, "unexpected_response",
                  "Device access_token missing in response");
     return RegisterDeviceError(callback, std::move(error));
   }
@@ -737,7 +728,7 @@
   if (!IsSuccessful(*response)) {
     ParseGCDError(json_resp.get(), &error);
     if (status_code == http::kForbidden &&
-        error->HasError(kErrorDomainGCDServer, "rateLimitExceeded")) {
+        error->HasError("rateLimitExceeded")) {
       // If we exceeded server quota, retry the request later.
       return RetryCloudRequest(data);
     }
@@ -770,13 +761,13 @@
 }
 
 void DeviceRegistrationInfo::CheckAccessTokenError(ErrorPtr error) {
-  if (error && error->HasError(kErrorDomainOAuth2, "invalid_grant"))
+  if (error && error->HasError("invalid_grant"))
     RemoveCredentials();
 }
 
 void DeviceRegistrationInfo::ConnectToCloud(ErrorPtr error) {
   if (error) {
-    if (error->HasError(kErrorDomainOAuth2, "invalid_grant"))
+    if (error->HasError("invalid_grant"))
       RemoveCredentials();
     return;
   }
@@ -844,9 +835,8 @@
     const std::string& service_url,
     ErrorPtr* error) {
   if (HaveRegistrationCredentials()) {
-    Error::AddTo(error, FROM_HERE, errors::kErrorDomain, kErrorAlreayRegistered,
-                 "Unable to change config for registered device");
-    return false;
+    return Error::AddTo(error, FROM_HERE, kErrorAlreayRegistered,
+                        "Unable to change config for registered device");
   }
   Config::Transaction change{config_};
   change.set_client_id(client_id);
@@ -1012,7 +1002,7 @@
 }
 
 void DeviceRegistrationInfo::OnUpdateDeviceResourceError(ErrorPtr error) {
-  if (error->HasError(kErrorDomainGCDServer, "invalid_last_update_time_ms")) {
+  if (error->HasError("invalid_last_update_time_ms")) {
     // If the server rejected our previous request, retrieve the latest
     // timestamp from the server and retry.
     VLOG(1) << "Getting the last device resource timestamp from server...";
diff --git a/src/device_registration_info.h b/src/device_registration_info.h
index 4a1c925..f670b68 100644
--- a/src/device_registration_info.h
+++ b/src/device_registration_info.h
@@ -45,10 +45,6 @@
 class AuthManager;
 }
 
-extern const char kErrorDomainOAuth2[];
-extern const char kErrorDomainGCD[];
-extern const char kErrorDomainGCDServer[];
-
 // The DeviceRegistrationInfo class represents device registration information.
 class DeviceRegistrationInfo : public NotificationDelegate,
                                public CloudCommandUpdateInterface {
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc
index 595d749..cd11ac9 100644
--- a/src/device_registration_info_unittest.cc
+++ b/src/device_registration_info_unittest.cc
@@ -309,7 +309,7 @@
 
   ErrorPtr error;
   EXPECT_FALSE(RefreshAccessToken(&error));
-  EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "unable_to_authenticate"));
+  EXPECT_TRUE(error->HasError("unable_to_authenticate"));
   EXPECT_EQ(GcdState::kConnecting, GetGcdState());
 }
 
@@ -338,7 +338,7 @@
 
   ErrorPtr error;
   EXPECT_FALSE(RefreshAccessToken(&error));
-  EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "invalid_grant"));
+  EXPECT_TRUE(error->HasError("invalid_grant"));
   EXPECT_EQ(GcdState::kInvalidCredentials, GetGcdState());
   EXPECT_EQ(test_data::kCloudId, dev_reg_->GetSettings().cloud_id);
 }
@@ -567,7 +567,7 @@
   bool done = false;
   dev_reg_->RegisterDevice(
       test_data::kClaimTicketId, base::Bind([this, &done](ErrorPtr error) {
-        EXPECT_TRUE(error->HasError("weave", "already_registered"));
+        EXPECT_TRUE(error->HasError("already_registered"));
         done = true;
         task_runner_.Break();
         EXPECT_EQ(GcdState::kConnecting, GetGcdState());
diff --git a/src/error.cc b/src/error.cc
index 89071df..cb279c1 100644
--- a/src/error.cc
+++ b/src/error.cc
@@ -11,7 +11,6 @@
 
 namespace {
 inline void LogError(const tracked_objects::Location& location,
-                     const std::string& domain,
                      const std::string& code,
                      const std::string& message) {
   // Use logging::LogMessage() directly instead of LOG(ERROR) to substitute
@@ -22,66 +21,60 @@
                       logging::LOG_ERROR)
           .stream()
       << location.function_name() << "(...): "
-      << "Domain=" << domain << ", Code=" << code << ", Message=" << message;
+      << "Code=" << code << ", Message=" << message;
 }
 }  // anonymous namespace
 
 ErrorPtr Error::Create(const tracked_objects::Location& location,
-                       const std::string& domain,
                        const std::string& code,
                        const std::string& message) {
-  return Create(location, domain, code, message, ErrorPtr());
+  return Create(location, code, message, ErrorPtr());
 }
 
 ErrorPtr Error::Create(const tracked_objects::Location& location,
-                       const std::string& domain,
                        const std::string& code,
                        const std::string& message,
                        ErrorPtr inner_error) {
-  LogError(location, domain, code, message);
-  return ErrorPtr(
-      new Error(location, domain, code, message, std::move(inner_error)));
+  LogError(location, code, message);
+  return ErrorPtr(new Error(location, code, message, std::move(inner_error)));
 }
 
-void Error::AddTo(ErrorPtr* error,
-                  const tracked_objects::Location& location,
-                  const std::string& domain,
-                  const std::string& code,
-                  const std::string& message) {
+Error::AddToTypeProxy Error::AddTo(ErrorPtr* error,
+                                   const tracked_objects::Location& location,
+                                   const std::string& code,
+                                   const std::string& message) {
   if (error) {
-    *error = Create(location, domain, code, message, std::move(*error));
+    *error = Create(location, code, message, std::move(*error));
   } else {
     // Create already logs the error, but if |error| is nullptr,
     // we still want to log the error...
-    LogError(location, domain, code, message);
+    LogError(location, code, message);
   }
+  return {};
 }
 
-void Error::AddToPrintf(ErrorPtr* error,
-                        const tracked_objects::Location& location,
-                        const std::string& domain,
-                        const std::string& code,
-                        const char* format,
-                        ...) {
+Error::AddToTypeProxy Error::AddToPrintf(
+    ErrorPtr* error,
+    const tracked_objects::Location& location,
+    const std::string& code,
+    const char* format,
+    ...) {
   va_list ap;
   va_start(ap, format);
   std::string message = base::StringPrintV(format, ap);
   va_end(ap);
-  AddTo(error, location, domain, code, message);
+  AddTo(error, location, code, message);
+  return {};
 }
 
 ErrorPtr Error::Clone() const {
   ErrorPtr inner_error = inner_error_ ? inner_error_->Clone() : nullptr;
   return ErrorPtr(
-      new Error(location_, domain_, code_, message_, std::move(inner_error)));
+      new Error(location_, code_, message_, std::move(inner_error)));
 }
 
-bool Error::HasDomain(const std::string& domain) const {
-  return FindErrorOfDomain(this, domain) != nullptr;
-}
-
-bool Error::HasError(const std::string& domain, const std::string& code) const {
-  return FindError(this, domain, code) != nullptr;
+bool Error::HasError(const std::string& code) const {
+  return FindError(this, code) != nullptr;
 }
 
 const Error* Error::GetFirstError() const {
@@ -92,40 +85,25 @@
 }
 
 Error::Error(const tracked_objects::Location& location,
-             const std::string& domain,
              const std::string& code,
              const std::string& message,
              ErrorPtr inner_error)
-    : Error{tracked_objects::LocationSnapshot{location}, domain, code, message,
+    : Error{tracked_objects::LocationSnapshot{location}, code, message,
             std::move(inner_error)} {}
 
 Error::Error(const tracked_objects::LocationSnapshot& location,
-             const std::string& domain,
              const std::string& code,
              const std::string& message,
              ErrorPtr inner_error)
-    : domain_(domain),
-      code_(code),
+    : code_(code),
       message_(message),
       location_(location),
       inner_error_(std::move(inner_error)) {}
 
-const Error* Error::FindErrorOfDomain(const Error* error_chain_start,
-                                      const std::string& domain) {
-  while (error_chain_start) {
-    if (error_chain_start->GetDomain() == domain)
-      break;
-    error_chain_start = error_chain_start->GetInnerError();
-  }
-  return error_chain_start;
-}
-
 const Error* Error::FindError(const Error* error_chain_start,
-                              const std::string& domain,
                               const std::string& code) {
   while (error_chain_start) {
-    if (error_chain_start->GetDomain() == domain &&
-        error_chain_start->GetCode() == code)
+    if (error_chain_start->GetCode() == code)
       break;
     error_chain_start = error_chain_start->GetInnerError();
   }
diff --git a/src/error_unittest.cc b/src/error_unittest.cc
index 85633de..0486e86 100644
--- a/src/error_unittest.cc
+++ b/src/error_unittest.cc
@@ -13,50 +13,37 @@
 ErrorPtr GenerateNetworkError() {
   tracked_objects::Location loc("GenerateNetworkError", "error_unittest.cc", 15,
                                 ::tracked_objects::GetProgramCounter());
-  return Error::Create(loc, "network", "not_found", "Resource not found");
+  return Error::Create(loc, "not_found", "Resource not found");
 }
 
 ErrorPtr GenerateHttpError() {
   ErrorPtr inner = GenerateNetworkError();
-  return Error::Create(FROM_HERE, "HTTP", "404", "Not found", std::move(inner));
+  return Error::Create(FROM_HERE, "404", "Not found", std::move(inner));
 }
 
 }  // namespace
 
 TEST(Error, Single) {
   ErrorPtr err = GenerateNetworkError();
-  EXPECT_EQ("network", err->GetDomain());
   EXPECT_EQ("not_found", err->GetCode());
   EXPECT_EQ("Resource not found", err->GetMessage());
   EXPECT_EQ("GenerateNetworkError", err->GetLocation().function_name);
   EXPECT_EQ("error_unittest.cc", err->GetLocation().file_name);
   EXPECT_EQ(15, err->GetLocation().line_number);
   EXPECT_EQ(nullptr, err->GetInnerError());
-  EXPECT_TRUE(err->HasDomain("network"));
-  EXPECT_FALSE(err->HasDomain("HTTP"));
-  EXPECT_FALSE(err->HasDomain("foo"));
-  EXPECT_TRUE(err->HasError("network", "not_found"));
-  EXPECT_FALSE(err->HasError("network", "404"));
-  EXPECT_FALSE(err->HasError("HTTP", "404"));
-  EXPECT_FALSE(err->HasError("HTTP", "not_found"));
-  EXPECT_FALSE(err->HasError("foo", "bar"));
+  EXPECT_TRUE(err->HasError("not_found"));
+  EXPECT_FALSE(err->HasError("404"));
+  EXPECT_FALSE(err->HasError("bar"));
 }
 
 TEST(Error, Nested) {
   ErrorPtr err = GenerateHttpError();
-  EXPECT_EQ("HTTP", err->GetDomain());
   EXPECT_EQ("404", err->GetCode());
   EXPECT_EQ("Not found", err->GetMessage());
   EXPECT_NE(nullptr, err->GetInnerError());
-  EXPECT_EQ("network", err->GetInnerError()->GetDomain());
-  EXPECT_TRUE(err->HasDomain("network"));
-  EXPECT_TRUE(err->HasDomain("HTTP"));
-  EXPECT_FALSE(err->HasDomain("foo"));
-  EXPECT_TRUE(err->HasError("network", "not_found"));
-  EXPECT_FALSE(err->HasError("network", "404"));
-  EXPECT_TRUE(err->HasError("HTTP", "404"));
-  EXPECT_FALSE(err->HasError("HTTP", "not_found"));
-  EXPECT_FALSE(err->HasError("foo", "bar"));
+  EXPECT_TRUE(err->HasError("not_found"));
+  EXPECT_TRUE(err->HasError("404"));
+  EXPECT_FALSE(err->HasError("bar"));
 }
 
 TEST(Error, Clone) {
@@ -66,7 +53,6 @@
   const Error* error2 = clone.get();
   while (error1 && error2) {
     EXPECT_NE(error1, error2);
-    EXPECT_EQ(error1->GetDomain(), error2->GetDomain());
     EXPECT_EQ(error1->GetCode(), error2->GetCode());
     EXPECT_EQ(error1->GetMessage(), error2->GetMessage());
     EXPECT_EQ(error1->GetLocation().function_name,
diff --git a/src/json_error_codes.cc b/src/json_error_codes.cc
index 9bfaef0..647c0ba 100644
--- a/src/json_error_codes.cc
+++ b/src/json_error_codes.cc
@@ -8,7 +8,6 @@
 namespace errors {
 
 namespace json {
-const char kDomain[] = "json_parser";
 const char kParseError[] = "json_parse_error";
 const char kObjectExpected[] = "json_object_expected";
 }  // namespace json
diff --git a/src/json_error_codes.h b/src/json_error_codes.h
index 5d3f07b..551eaac 100644
--- a/src/json_error_codes.h
+++ b/src/json_error_codes.h
@@ -10,8 +10,6 @@
 namespace errors {
 
 namespace json {
-extern const char kDomain[];
-
 extern const char kParseError[];
 extern const char kObjectExpected[];
 }  // namespace json
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index 8373a7e..66d04c4 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -65,15 +65,13 @@
                      ErrorPtr* error) {
   UwMacaroonCaveatType caveat_type{};
   if (!uw_macaroon_caveat_get_type_(&caveat, &caveat_type)) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, kInvalidTokenError,
-                 "Unable to get type");
-    return false;
+    return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
+                        "Unable to get type");
   }
 
   if (caveat_type != type) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, kInvalidTokenError,
-                 "Unexpected caveat type");
-    return false;
+    return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
+                        "Unexpected caveat type");
   }
 
   return true;
@@ -87,9 +85,8 @@
     return false;
 
   if (!uw_macaroon_caveat_get_value_uint_(&caveat, value)) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, kInvalidTokenError,
-                 "Unable to read caveat");
-    return false;
+    return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
+                        "Unable to read caveat");
   }
 
   return true;
@@ -105,9 +102,8 @@
   const uint8_t* start{nullptr};
   size_t size{0};
   if (!uw_macaroon_caveat_get_value_str_(&caveat, &start, &size)) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, kInvalidTokenError,
-                 "Unable to read caveat");
-    return false;
+    return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
+                        "Unable to read caveat");
   }
 
   value->assign(reinterpret_cast<const char*>(start), size);
@@ -147,9 +143,8 @@
   buffer->resize(kMaxMacaroonSize);
   if (!uw_macaroon_load_(token.data(), token.size(), buffer->data(),
                          buffer->size(), macaroon)) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, kInvalidTokenError,
-                 "Invalid token format");
-    return false;
+    return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
+                        "Invalid token format");
   }
   return true;
 }
@@ -159,9 +154,8 @@
                     ErrorPtr* error) {
   CHECK_EQ(kSha256OutputSize, secret.size());
   if (!uw_macaroon_verify_(&macaroon, secret.data(), secret.size())) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, "invalid_signature",
-                 "Invalid token signature");
-    return false;
+    return Error::AddTo(error, FROM_HERE, "invalid_signature",
+                        "Invalid token signature");
   }
   return true;
 }
@@ -275,23 +269,20 @@
                   &user_id, error) ||
       !ReadCaveat(macaroon.caveats[2], kUwMacaroonCaveatTypeExpiration,
                   &expiration, error)) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain,
-                 errors::kInvalidAuthorization, "Invalid token");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
+                        "Invalid token");
   }
 
   AuthScope auth_scope{FromMacaroonScope(scope)};
   if (auth_scope == AuthScope::kNone) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain,
-                 errors::kInvalidAuthorization, "Invalid token data");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
+                        "Invalid token data");
   }
 
   base::Time time{base::Time::FromTimeT(expiration)};
   if (time < clock_->Now()) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain,
-                 errors::kAuthorizationExpired, "Token is expired");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kAuthorizationExpired,
+                        "Token is expired");
   }
 
   if (user_info)
@@ -307,9 +298,9 @@
   if (config_) {
     auto current = config_->GetSettings().root_client_token_owner;
     if (!IsClaimAllowed(current, owner)) {
-      Error::AddToPrintf(
-          error, FROM_HERE, errors::kDomain, errors::kAlreadyClaimed,
-          "Device already claimed by '%s'", EnumToString(current).c_str());
+      Error::AddToPrintf(error, FROM_HERE, errors::kAlreadyClaimed,
+                         "Device already claimed by '%s'",
+                         EnumToString(current).c_str());
       return {};
     }
   };
@@ -333,9 +324,7 @@
                      return auth.first->IsValidAuthToken(token, nullptr);
                    });
   if (claim == pending_claims_.end()) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kNotFound,
-                 "Unknown claim");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kNotFound, "Unknown claim");
   }
 
   SetAuthSecret(claim->first->GetAuthSecret(), claim->second);
@@ -363,9 +352,8 @@
   UwMacaroon macaroon{};
   if (!LoadMacaroon(token, &buffer, &macaroon, error) ||
       !VerifyMacaroon(auth_secret_, macaroon, error)) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthCode,
-                 "Invalid token");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
+                        "Invalid token");
   }
   return true;
 }
diff --git a/src/privet/cloud_delegate.cc b/src/privet/cloud_delegate.cc
index 4bf47b3..5f31fee 100644
--- a/src/privet/cloud_delegate.cc
+++ b/src/privet/cloud_delegate.cc
@@ -32,7 +32,7 @@
 
 CommandInstance* ReturnNotFound(const std::string& command_id,
                                 ErrorPtr* error) {
-  Error::AddToPrintf(error, FROM_HERE, errors::kDomain, errors::kNotFound,
+  Error::AddToPrintf(error, FROM_HERE, errors::kNotFound,
                      "Command not found, ID='%s'", command_id.c_str());
   return nullptr;
 }
@@ -171,9 +171,8 @@
     UserRole role;
     std::string str_scope = EnumToString(user_info.scope());
     if (!StringToEnum(str_scope, &role)) {
-      Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                         errors::kInvalidParams, "Invalid role: '%s'",
-                         str_scope.c_str());
+      Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                         "Invalid role: '%s'", str_scope.c_str());
       return callback.Run({}, std::move(error));
     }
 
@@ -251,9 +250,9 @@
       connection_state_ = ConnectionState{ConnectionState::kOnline};
     } else {
       ErrorPtr error;
-      Error::AddToPrintf(
-          &error, FROM_HERE, errors::kDomain, errors::kInvalidState,
-          "Unexpected registration status: %s", EnumToString(status).c_str());
+      Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidState,
+                         "Unexpected registration status: %s",
+                         EnumToString(status).c_str());
       connection_state_ = ConnectionState{std::move(error)};
     }
     NotifyOnDeviceInfoChanged();
@@ -268,7 +267,7 @@
     ErrorPtr error;
     CHECK_GE(registation_retry_count_, 0);
     if (registation_retry_count_-- == 0) {
-      Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kInvalidState,
+      Error::AddTo(&error, FROM_HERE, errors::kInvalidState,
                    "Failed to register device");
       setup_state_ = SetupState{std::move(error)};
       return;
@@ -321,9 +320,8 @@
       return true;
     }
 
-    Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kAccessDenied,
-                 "Need to be owner of the command.");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kAccessDenied,
+                        "Need to be owner of the command.");
   }
 
   provider::TaskRunner* task_runner_{nullptr};
diff --git a/src/privet/constants.cc b/src/privet/constants.cc
index e1962bd..4278165 100644
--- a/src/privet/constants.cc
+++ b/src/privet/constants.cc
@@ -8,8 +8,6 @@
 namespace privet {
 namespace errors {
 
-const char kDomain[] = "privetd";
-
 const char kInvalidClientCommitment[] = "invalidClientCommitment";
 const char kInvalidFormat[] = "invalidFormat";
 const char kMissingAuthorization[] = "missingAuthorization";
diff --git a/src/privet/constants.h b/src/privet/constants.h
index 2b001aa..67f993d 100644
--- a/src/privet/constants.h
+++ b/src/privet/constants.h
@@ -10,8 +10,6 @@
 
 namespace errors {
 
-extern const char kDomain[];
-
 extern const char kInvalidClientCommitment[];
 extern const char kInvalidFormat[];
 extern const char kMissingAuthorization[];
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc
index db55861..e8b1c77 100644
--- a/src/privet/privet_handler.cc
+++ b/src/privet/privet_handler.cc
@@ -185,7 +185,7 @@
                  const PrivetHandler::RequestCallback& callback) {
   int code = http::kInternalServerError;
   for (const auto& it : kReasonToCode) {
-    if (error.HasError(errors::kDomain, it.reason)) {
+    if (error.HasError(it.reason)) {
       code = it.code;
       break;
     }
@@ -201,14 +201,12 @@
   if (!error)
     return callback.Run(http::kOk, output);
 
-  if (error->HasError("gcd", "unknown_command")) {
-    Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kNotFound,
-                 "Unknown command ID");
+  if (error->HasError("unknown_command")) {
+    Error::AddTo(&error, FROM_HERE, errors::kNotFound, "Unknown command ID");
     return ReturnError(*error, callback);
   }
-  if (error->HasError("gcd", "access_denied")) {
-    Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kAccessDenied,
-                 error->GetMessage());
+  if (error->HasError("access_denied")) {
+    Error::AddTo(&error, FROM_HERE, errors::kAccessDenied, error->GetMessage());
     return ReturnError(*error, callback);
   }
   return ReturnError(*error, callback);
@@ -471,26 +469,22 @@
                                   const RequestCallback& callback) {
   ErrorPtr error;
   if (!input) {
-    Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kInvalidFormat,
-                 "Malformed JSON");
+    Error::AddTo(&error, FROM_HERE, errors::kInvalidFormat, "Malformed JSON");
     return ReturnError(*error, callback);
   }
   auto handler = handlers_.find(api);
   if (handler == handlers_.end()) {
-    Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kNotFound,
-                 "Path not found");
+    Error::AddTo(&error, FROM_HERE, errors::kNotFound, "Path not found");
     return ReturnError(*error, callback);
   }
   if (auth_header.empty()) {
-    Error::AddTo(&error, FROM_HERE, errors::kDomain,
-                 errors::kMissingAuthorization,
+    Error::AddTo(&error, FROM_HERE, errors::kMissingAuthorization,
                  "Authorization header must not be empty");
     return ReturnError(*error, callback);
   }
   std::string token = GetAuthTokenFromAuthHeader(auth_header);
   if (token.empty()) {
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidAuthorization,
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidAuthorization,
                        "Invalid authorization header: %s", auth_header.c_str());
     return ReturnError(*error, callback);
   }
@@ -501,8 +495,7 @@
   }
 
   if (handler->second.scope > user_info.scope()) {
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidAuthorizationScope,
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidAuthorizationScope,
                        "Scope '%s' does not allow '%s'",
                        EnumToString(user_info.scope()).c_str(), api.c_str());
     return ReturnError(*error, callback);
@@ -590,9 +583,9 @@
   std::set<PairingType> modes = security_->GetPairingTypes();
   if (!StringToEnum(pairing_str, &pairing) ||
       modes.find(pairing) == modes.end()) {
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidParams, kInvalidParamValueFormat,
-                       kPairingKey, pairing_str.c_str());
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                       kInvalidParamValueFormat, kPairingKey,
+                       pairing_str.c_str());
     return ReturnError(*error, callback);
   }
 
@@ -600,9 +593,9 @@
   std::set<CryptoType> cryptos = security_->GetCryptoTypes();
   if (!StringToEnum(crypto_str, &crypto) ||
       cryptos.find(crypto) == cryptos.end()) {
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidParams, kInvalidParamValueFormat,
-                       kCryptoKey, crypto_str.c_str());
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                       kInvalidParamValueFormat, kCryptoKey,
+                       crypto_str.c_str());
     return ReturnError(*error, callback);
   }
 
@@ -663,9 +656,9 @@
   AuthType auth_type{};
   if (!input.GetString(kAuthModeKey, &auth_code_type) ||
       !StringToEnum(auth_code_type, &auth_type)) {
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidAuthMode, kInvalidParamValueFormat,
-                       kAuthModeKey, auth_code_type.c_str());
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidAuthMode,
+                       kInvalidParamValueFormat, kAuthModeKey,
+                       auth_code_type.c_str());
     return ReturnError(*error, callback);
   }
 
@@ -676,8 +669,7 @@
   input.GetString(kAuthRequestedScopeKey, &requested_scope);
   if (requested_scope != kAuthScopeAutoValue) {
     if (!StringToEnum(requested_scope, &desired_scope)) {
-      Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                         errors::kInvalidRequestedScope,
+      Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidRequestedScope,
                          kInvalidParamValueFormat, kAuthRequestedScopeKey,
                          requested_scope.c_str());
       return ReturnError(*error, callback);
@@ -701,8 +693,8 @@
   }
 
   if (access_token_scope < acceptable_scope) {
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kAccessDenied, "Scope '%s' is not allowed",
+    Error::AddToPrintf(&error, FROM_HERE, errors::kAccessDenied,
+                       "Scope '%s' is not allowed",
                        EnumToString(access_token_scope).c_str());
     return ReturnError(*error, callback);
   }
@@ -737,9 +729,9 @@
 
   std::string token;
   if (!input.GetString(kAuthClientTokenKey, &token)) {
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidParams, kInvalidParamValueFormat,
-                       kAuthClientTokenKey, token.c_str());
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                       kInvalidParamValueFormat, kAuthClientTokenKey,
+                       token.c_str());
     return ReturnError(*error, callback);
   }
 
@@ -771,16 +763,15 @@
   if (input.GetDictionary(kWifiKey, &wifi)) {
     if (!wifi_ || wifi_->GetTypes().empty()) {
       ErrorPtr error;
-      Error::AddTo(&error, FROM_HERE, errors::kDomain,
-                   errors::kSetupUnavailable, "WiFi setup unavailable");
+      Error::AddTo(&error, FROM_HERE, errors::kSetupUnavailable,
+                   "WiFi setup unavailable");
       return ReturnError(*error, callback);
     }
     wifi->GetString(kSetupStartSsidKey, &ssid);
     if (ssid.empty()) {
       ErrorPtr error;
-      Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                         errors::kInvalidParams, kInvalidParamValueFormat,
-                         kSetupStartSsidKey, "");
+      Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                         kInvalidParamValueFormat, kSetupStartSsidKey, "");
       return ReturnError(*error, callback);
     }
     wifi->GetString(kSetupStartPassKey, &passphrase);
@@ -790,17 +781,15 @@
   if (input.GetDictionary(kGcdKey, &registration)) {
     if (user_info.scope() < AuthScope::kOwner) {
       ErrorPtr error;
-      Error::AddTo(&error, FROM_HERE, errors::kDomain,
-                   errors::kInvalidAuthorizationScope,
+      Error::AddTo(&error, FROM_HERE, errors::kInvalidAuthorizationScope,
                    "Only owner can register device");
       return ReturnError(*error, callback);
     }
     registration->GetString(kSetupStartTicketIdKey, &ticket);
     if (ticket.empty()) {
       ErrorPtr error;
-      Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                         errors::kInvalidParams, kInvalidParamValueFormat,
-                         kSetupStartTicketIdKey, "");
+      Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                         kInvalidParamValueFormat, kSetupStartTicketIdKey, "");
       return ReturnError(*error, callback);
     }
     registration->GetString(kSetupStartUserKey, &user);
@@ -932,9 +921,8 @@
   std::string id;
   if (!input.GetString(kCommandsIdKey, &id)) {
     ErrorPtr error;
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidParams, kInvalidParamValueFormat,
-                       kCommandsIdKey, id.c_str());
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                       kInvalidParamValueFormat, kCommandsIdKey, id.c_str());
     return ReturnError(*error, callback);
   }
   cloud_->GetCommand(id, user_info,
@@ -954,9 +942,8 @@
   std::string id;
   if (!input.GetString(kCommandsIdKey, &id)) {
     ErrorPtr error;
-    Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidParams, kInvalidParamValueFormat,
-                       kCommandsIdKey, id.c_str());
+    Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
+                       kInvalidParamValueFormat, kCommandsIdKey, id.c_str());
     return ReturnError(*error, callback);
   }
   cloud_->CancelCommand(id, user_info,
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc
index 6d6a289..fa79e77 100644
--- a/src/privet/privet_handler_unittest.cc
+++ b/src/privet/privet_handler_unittest.cc
@@ -136,7 +136,7 @@
         .WillRepeatedly(ReturnRef(gcd_disabled_state_));
     auto set_error = [](const std::string&, const std::string&,
                         ErrorPtr* error) {
-      Error::AddTo(error, FROM_HERE, errors::kDomain, "setupUnavailable", "");
+      Error::AddTo(error, FROM_HERE, "setupUnavailable", "");
     };
     EXPECT_CALL(cloud_, Setup(_, _, _))
         .WillRepeatedly(DoAll(Invoke(set_error), Return(false)));
@@ -197,11 +197,9 @@
 TEST_F(PrivetHandlerTest, ExpiredAuth) {
   auth_header_ = "Privet 123";
   EXPECT_CALL(security_, ParseAccessToken(_, _, _))
-      .WillRepeatedly(DoAll(WithArgs<2>(Invoke([](ErrorPtr* error) {
-                              Error::AddTo(error, FROM_HERE, errors::kDomain,
-                                           "authorizationExpired", "");
-                            })),
-                            Return(false)));
+      .WillRepeatedly(WithArgs<2>(Invoke([](ErrorPtr* error) {
+        return Error::AddTo(error, FROM_HERE, "authorizationExpired", "");
+      })));
   EXPECT_PRED2(IsEqualError, CodeWithReason(403, "authorizationExpired"),
                HandleRequest("/privet/info", "{}"));
 }
@@ -379,10 +377,10 @@
 
 TEST_F(PrivetHandlerTest, AuthErrorInvalidAuthCode) {
   auto set_error = [](ErrorPtr* error) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, "invalidAuthCode", "");
+    return Error::AddTo(error, FROM_HERE, "invalidAuthCode", "");
   };
   EXPECT_CALL(security_, CreateAccessToken(_, "testToken", _, _, _, _, _))
-      .WillRepeatedly(DoAll(WithArgs<6>(Invoke(set_error)), Return(false)));
+      .WillRepeatedly(WithArgs<6>(Invoke(set_error)));
   const char kInput[] = R"({
     'mode': 'pairing',
     'requestedScope': 'user',
@@ -511,7 +509,7 @@
 
 TEST_F(PrivetHandlerSetupTest, StatusWifiError) {
   ErrorPtr error;
-  Error::AddTo(&error, FROM_HERE, "test", "invalidPassphrase", "");
+  Error::AddTo(&error, FROM_HERE, "invalidPassphrase", "");
   wifi_.setup_state_ = SetupState{std::move(error)};
 
   const char kExpected[] = R"({
@@ -541,7 +539,7 @@
 
 TEST_F(PrivetHandlerSetupTest, StatusGcdError) {
   ErrorPtr error;
-  Error::AddTo(&error, FROM_HERE, "test", "invalidTicket", "");
+  Error::AddTo(&error, FROM_HERE, "invalidTicket", "");
   cloud_.setup_state_ = SetupState{std::move(error)};
 
   const char kExpected[] = R"({
@@ -601,10 +599,9 @@
     }
   })";
   auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, "deviceBusy", "");
+    return Error::AddTo(error, FROM_HERE, "deviceBusy", "");
   };
-  EXPECT_CALL(wifi_, ConfigureCredentials(_, _, _))
-      .WillOnce(DoAll(Invoke(set_error), Return(false)));
+  EXPECT_CALL(wifi_, ConfigureCredentials(_, _, _)).WillOnce(Invoke(set_error));
   EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"),
                HandleRequest("/privet/v3/setup/start", kInput));
 
@@ -641,10 +638,9 @@
   })";
 
   auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, "deviceBusy", "");
+    return Error::AddTo(error, FROM_HERE, "deviceBusy", "");
   };
-  EXPECT_CALL(cloud_, Setup(_, _, _))
-      .WillOnce(DoAll(Invoke(set_error), Return(false)));
+  EXPECT_CALL(cloud_, Setup(_, _, _)).WillOnce(Invoke(set_error));
   EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"),
                HandleRequest("/privet/v3/setup/start", kInput));
 
@@ -857,8 +853,7 @@
           "{'path':'comp1.comp2', 'filter':['traits', 'components']}"));
 
   auto error_handler = [](ErrorPtr* error) -> const base::DictionaryValue* {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, "componentNotFound", "");
-    return nullptr;
+    return Error::AddTo(error, FROM_HERE, "componentNotFound", "");
   };
   EXPECT_CALL(cloud_, FindComponent("comp7", _))
       .WillOnce(WithArgs<1>(Invoke(error_handler)));
@@ -899,7 +894,7 @@
                  HandleRequest("/privet/v3/commands/status", kInput));
 
   ErrorPtr error;
-  Error::AddTo(&error, FROM_HERE, errors::kDomain, "notFound", "");
+  Error::AddTo(&error, FROM_HERE, "notFound", "");
   EXPECT_CALL(cloud_, GetCommand(_, _, _))
       .WillOnce(WithArgs<2>(
           Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) {
@@ -924,7 +919,7 @@
                  HandleRequest("/privet/v3/commands/cancel", "{'id': '8'}"));
 
   ErrorPtr error;
-  Error::AddTo(&error, FROM_HERE, errors::kDomain, "notFound", "");
+  Error::AddTo(&error, FROM_HERE, "notFound", "");
   EXPECT_CALL(cloud_, CancelCommand(_, _, _))
       .WillOnce(WithArgs<2>(
           Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) {
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc
index 2a3dc08..358876d 100644
--- a/src/privet/security_manager.cc
+++ b/src/privet/security_manager.cc
@@ -51,9 +51,8 @@
       case crypto::P224EncryptedKeyExchange::kResultPending:
         return true;
       case crypto::P224EncryptedKeyExchange::kResultFailed:
-        Error::AddTo(error, FROM_HERE, errors::kDomain,
-                     errors::kInvalidClientCommitment, spake_.error());
-        return false;
+        return Error::AddTo(error, FROM_HERE, errors::kInvalidClientCommitment,
+                            spake_.error());
       default:
         LOG(FATAL) << "SecurityManager uses only one round trip";
     }
@@ -139,9 +138,8 @@
     base::TimeDelta* access_token_ttl,
     ErrorPtr* error) {
   auto disabled_mode = [](ErrorPtr* error) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthMode,
-                 "Mode is not available");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthMode,
+                        "Mode is not available");
   };
 
   switch (auth_type) {
@@ -154,9 +152,8 @@
       if (!IsPairingAuthSupported())
         return disabled_mode(error);
       if (!IsValidPairingCode(auth_code)) {
-        Error::AddTo(error, FROM_HERE, errors::kDomain,
-                     errors::kInvalidAuthCode, "Invalid authCode");
-        return false;
+        return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
+                            "Invalid authCode");
       }
       return CreateAccessTokenImpl(auth_type, desired_scope, access_token,
                                    access_token_scope, access_token_ttl);
@@ -170,9 +167,8 @@
           error);
   }
 
-  Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthMode,
-               "Unsupported auth mode");
-  return false;
+  return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthMode,
+                      "Unsupported auth mode");
 }
 
 bool SecurityManager::CreateAccessToken(AuthType auth_type,
@@ -185,8 +181,7 @@
   std::vector<uint8_t> auth_decoded;
   if (auth_type != AuthType::kAnonymous &&
       !Base64Decode(auth_code, &auth_decoded)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidAuthorization,
+    Error::AddToPrintf(error, FROM_HERE, errors::kInvalidAuthorization,
                        "Invalid auth_code encoding: %s", auth_code.c_str());
     return false;
   }
@@ -209,8 +204,7 @@
                                        ErrorPtr* error) const {
   std::vector<uint8_t> decoded;
   if (!Base64Decode(token, &decoded)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidAuthorization,
+    Error::AddToPrintf(error, FROM_HERE, errors::kInvalidAuthorization,
                        "Invalid token encoding: %s", token.c_str());
     return false;
   }
@@ -252,8 +246,7 @@
                                              ErrorPtr* error) {
   std::vector<uint8_t> token_decoded;
   if (!Base64Decode(token, &token_decoded)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
-                       errors::kInvalidFormat,
+    Error::AddToPrintf(error, FROM_HERE, errors::kInvalidFormat,
                        "Invalid auth token string: '%s'", token.c_str());
     return false;
   }
@@ -293,9 +286,8 @@
   const auto& pairing_modes = GetSettings().pairing_modes;
   if (std::find(pairing_modes.begin(), pairing_modes.end(), mode) ==
       pairing_modes.end()) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidParams,
-                 "Pairing mode is not enabled");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kInvalidParams,
+                        "Pairing mode is not enabled");
   }
 
   std::string code;
@@ -308,9 +300,8 @@
       code = base::StringPrintf("%04i", base::RandInt(0, 9999));
       break;
     default:
-      Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidParams,
-                   "Unsupported pairing mode");
-      return false;
+      return Error::AddTo(error, FROM_HERE, errors::kInvalidParams,
+                          "Unsupported pairing mode");
   }
 
   std::unique_ptr<KeyExchanger> spake;
@@ -325,9 +316,8 @@
       }
     // Fall through...
     default:
-      Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidParams,
-                   "Unsupported crypto");
-      return false;
+      return Error::AddTo(error, FROM_HERE, errors::kInvalidParams,
+                          "Unsupported crypto");
   }
 
   // Allow only a single session at a time for now.
@@ -368,27 +358,25 @@
                                      ErrorPtr* error) {
   auto session = pending_sessions_.find(session_id);
   if (session == pending_sessions_.end()) {
-    Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
-                       errors::kUnknownSession, "Unknown session id: '%s'",
-                       session_id.c_str());
+    Error::AddToPrintf(error, FROM_HERE, errors::kUnknownSession,
+                       "Unknown session id: '%s'", session_id.c_str());
     return false;
   }
 
   std::vector<uint8_t> commitment;
   if (!Base64Decode(client_commitment, &commitment)) {
     ClosePendingSession(session_id);
-    Error::AddToPrintf(
-        error, FROM_HERE, errors::kDomain, errors::kInvalidFormat,
-        "Invalid commitment string: '%s'", client_commitment.c_str());
+    Error::AddToPrintf(error, FROM_HERE, errors::kInvalidFormat,
+                       "Invalid commitment string: '%s'",
+                       client_commitment.c_str());
     return false;
   }
 
   if (!session->second->ProcessMessage(
           std::string(commitment.begin(), commitment.end()), error)) {
     ClosePendingSession(session_id);
-    Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kCommitmentMismatch,
-                 "Pairing code or crypto implementation mismatch");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kCommitmentMismatch,
+                        "Pairing code or crypto implementation mismatch");
   }
 
   const std::string& key = session->second->GetKey();
@@ -422,7 +410,7 @@
   CHECK(!confirmed || !pending);
   if (confirmed || pending)
     return true;
-  Error::AddToPrintf(error, FROM_HERE, errors::kDomain, errors::kUnknownSession,
+  Error::AddToPrintf(error, FROM_HERE, errors::kUnknownSession,
                      "Unknown session id: '%s'", session_id.c_str());
   return false;
 }
@@ -444,9 +432,8 @@
     return true;
 
   if (block_pairing_until_ > auth_manager_->Now()) {
-    Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kDeviceBusy,
-                 "Too many pairing attempts");
-    return false;
+    return Error::AddTo(error, FROM_HERE, errors::kDeviceBusy,
+                        "Too many pairing attempts");
   }
 
   if (++pairing_attemts_ >= kMaxAllowedPairingAttemts) {
diff --git a/src/privet/wifi_bootstrap_manager.cc b/src/privet/wifi_bootstrap_manager.cc
index 086e21c..566da80 100644
--- a/src/privet/wifi_bootstrap_manager.cc
+++ b/src/privet/wifi_bootstrap_manager.cc
@@ -211,7 +211,7 @@
 void WifiBootstrapManager::OnConnectDone(const std::string& ssid,
                                          ErrorPtr error) {
   if (error) {
-    Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kInvalidState,
+    Error::AddTo(&error, FROM_HERE, errors::kInvalidState,
                  "Failed to connect to provided network");
     setup_state_ = SetupState{std::move(error)};
     return StartBootstrapping();
@@ -226,7 +226,7 @@
 
 void WifiBootstrapManager::OnConnectTimeout() {
   ErrorPtr error;
-  Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kInvalidState,
+  Error::AddTo(&error, FROM_HERE, errors::kInvalidState,
                "Timeout connecting to provided network");
   setup_state_ = SetupState{std::move(error)};
   return StartBootstrapping();
@@ -265,7 +265,7 @@
     case Network::State::kError: {
       // TODO(wiley) Pull error information from somewhere.
       ErrorPtr error;
-      Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kInvalidState,
+      Error::AddTo(&error, FROM_HERE, errors::kInvalidState,
                    "Unknown WiFi error");
       connection_state_ = ConnectionState{std::move(error)};
       return;
@@ -278,7 +278,7 @@
       return;
   }
   ErrorPtr error;
-  Error::AddToPrintf(&error, FROM_HERE, errors::kDomain, errors::kInvalidState,
+  Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidState,
                      "Unknown network state: %s",
                      EnumToString(service_state).c_str());
   connection_state_ = ConnectionState{std::move(error)};
diff --git a/src/utils.cc b/src/utils.cc
index 24ce1ca..28828d7 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -29,7 +29,6 @@
 }  // anonymous namespace
 
 namespace errors {
-const char kErrorDomain[] = "weave";
 const char kSchemaError[] = "schema_error";
 const char kInvalidCategoryError[] = "invalid_category";
 const char kInvalidPackageError[] = "invalid_package";
@@ -43,8 +42,7 @@
   auto value = base::JSONReader::ReadAndReturnError(
       json_string, base::JSON_PARSE_RFC, nullptr, &error_message);
   if (!value) {
-    Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
-                       errors::json::kParseError,
+    Error::AddToPrintf(error, FROM_HERE, errors::json::kParseError,
                        "Error parsing JSON string '%s' (%zu): %s",
                        LimitString(json_string, kMaxStrLen).c_str(),
                        json_string.size(), error_message.c_str());
@@ -52,8 +50,7 @@
   }
   base::DictionaryValue* dict_value = nullptr;
   if (!value->GetAsDictionary(&dict_value)) {
-    Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
-                       errors::json::kObjectExpected,
+    Error::AddToPrintf(error, FROM_HERE, errors::json::kObjectExpected,
                        "JSON string '%s' is not a JSON object",
                        LimitString(json_string, kMaxStrLen).c_str());
     return result;
diff --git a/src/utils.h b/src/utils.h
index bd69e94..99d7bda 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -14,7 +14,6 @@
 namespace weave {
 
 namespace errors {
-extern const char kErrorDomain[];
 extern const char kSchemaError[];
 extern const char kInvalidCategoryError[];
 extern const char kInvalidPackageError[];
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc
index 8df63ae..ebc66cd 100644
--- a/src/weave_unittest.cc
+++ b/src/weave_unittest.cc
@@ -428,13 +428,12 @@
   EXPECT_TRUE(done);
 
   done = false;
-  device_->Register(
-      "TICKET_ID2", base::Bind([this, &done](ErrorPtr error) {
-        EXPECT_TRUE(error->HasError("weave", "already_registered"));
-        done = true;
-        task_runner_.Break();
-        EXPECT_EQ("CLOUD_ID", device_->GetSettings().cloud_id);
-      }));
+  device_->Register("TICKET_ID2", base::Bind([this, &done](ErrorPtr error) {
+                      EXPECT_TRUE(error->HasError("already_registered"));
+                      done = true;
+                      task_runner_.Break();
+                      EXPECT_EQ("CLOUD_ID", device_->GetSettings().cloud_id);
+                    }));
   task_runner_.Run();
   EXPECT_TRUE(done);
 }
diff --git a/tests.mk b/tests.mk
index 1ae3b81..4e11f7e 100644
--- a/tests.mk
+++ b/tests.mk
@@ -26,10 +26,17 @@
 
 $(weave_unittest_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/gtest/gtest.h
 	mkdir -p $(dir $@)
-	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
+	$(CXX) $(DEFS_TEST) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
-out/$(BUILD_MODE)/libweave_testrunner : $(weave_unittest_obj_files) $(third_party_chromium_crypto_unittest_obj_files) $(third_party_chromium_base_unittest_obj_files) out/$(BUILD_MODE)/libweave_common.a out/$(BUILD_MODE)/libweave-test.a
-	$(CXX) -o $@ $^ $(CFLAGS) -lcrypto -lexpat -lgmock -lgtest -lpthread -lrt -Lthird_party/lib
+out/$(BUILD_MODE)/libweave_testrunner : \
+	$(weave_unittest_obj_files) \
+	$(third_party_chromium_crypto_unittest_obj_files) \
+	$(third_party_chromium_base_unittest_obj_files) \
+	out/$(BUILD_MODE)/libweave_common.a \
+	out/$(BUILD_MODE)/libweave-test.a \
+	third_party/lib/gmock.a \
+	third_party/lib/gtest.a
+	$(CXX) -o $@ $^ $(CFLAGS) -lcrypto -lexpat -lpthread -lrt -Lthird_party/lib
 
 test : out/$(BUILD_MODE)/libweave_testrunner
 	$(TEST_ENV) $< $(TEST_FLAGS)
@@ -41,10 +48,16 @@
 
 $(weave_exports_unittest_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/gtest/gtest.h
 	mkdir -p $(dir $@)
-	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
+	$(CXX) $(DEFS_TEST) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
-out/$(BUILD_MODE)/libweave_exports_testrunner : $(weave_exports_unittest_obj_files) out/$(BUILD_MODE)/libweave.so out/$(BUILD_MODE)/libweave-test.a out/$(BUILD_MODE)/src/test/weave_testrunner.o
-	$(CXX) -o $@ $^ $(CFLAGS) -lcrypto -lexpat -lgmock -lgtest -lpthread -lrt -Lthird_party/lib -Wl,-rpath=out/$(BUILD_MODE)/
+out/$(BUILD_MODE)/libweave_exports_testrunner : \
+	$(weave_exports_unittest_obj_files) \
+	out/$(BUILD_MODE)/libweave.so \
+	out/$(BUILD_MODE)/libweave-test.a \
+	out/$(BUILD_MODE)/src/test/weave_testrunner.o \
+	third_party/lib/gmock.a \
+	third_party/lib/gtest.a
+	$(CXX) -o $@ $^ $(CFLAGS) -lcrypto -lexpat -lpthread -lrt -Lthird_party/lib -Wl,-rpath=out/$(BUILD_MODE)/
 
 export-test : out/$(BUILD_MODE)/libweave_exports_testrunner
 	$(TEST_ENV) $< $(TEST_FLAGS)
diff --git a/third_party/chromium/base/compiler_specific.h b/third_party/chromium/base/compiler_specific.h
index 339e9b7..79b7fa8 100644
--- a/third_party/chromium/base/compiler_specific.h
+++ b/third_party/chromium/base/compiler_specific.h
@@ -135,7 +135,7 @@
 // |dots_param| is the one-based index of the "..." parameter.
 // For v*printf functions (which take a va_list), pass 0 for dots_param.
 // (This is undocumented but matches what the system C headers do.)
-#if defined(COMPILER_GCC)
+#if defined(COMPILER_GCC) || defined(__clang__)
 #define PRINTF_FORMAT(format_param, dots_param) \
     __attribute__((format(printf, format_param, dots_param)))
 #else
diff --git a/third_party/chromium/base/gtest_prod_util.h b/third_party/chromium/base/gtest_prod_util.h
index b90cd4e..b3db728 100644
--- a/third_party/chromium/base/gtest_prod_util.h
+++ b/third_party/chromium/base/gtest_prod_util.h
@@ -5,6 +5,8 @@
 #ifndef BASE_GTEST_PROD_UTIL_H_
 #define BASE_GTEST_PROD_UTIL_H_
 
+#if defined(HAS_GTEST)
+
 #include <gtest/gtest_prod.h>
 
 // This is a wrapper for gtest's FRIEND_TEST macro that friends
@@ -63,4 +65,10 @@
   class test_case_name##_##DISABLED_##test_name##_Test; \
   class test_case_name##_##FLAKY_##test_name##_Test
 
+#else  // defined(HAS_GTEST)
+
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name)
+
+#endif  // defined(HAS_GTEST)
+
 #endif  // BASE_GTEST_PROD_UTIL_H_
diff --git a/third_party/chromium/base/strings/stringprintf.cc b/third_party/chromium/base/strings/stringprintf.cc
index 8147ed3..c3ef88c 100644
--- a/third_party/chromium/base/strings/stringprintf.cc
+++ b/third_party/chromium/base/strings/stringprintf.cc
@@ -27,7 +27,10 @@
                       size_t buf_size,
                       const char* format,
                       va_list argptr) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
   return base::vsnprintf(buffer, buf_size, format, argptr);
+#pragma GCC diagnostic pop
 }
 
 // Templatized backend for StringPrintF/StringAppendF. This does not finalize
diff --git a/third_party/chromium/base/strings/stringprintf_unittest.cc b/third_party/chromium/base/strings/stringprintf_unittest.cc
index e70499d..7e9b13c 100644
--- a/third_party/chromium/base/strings/stringprintf_unittest.cc
+++ b/third_party/chromium/base/strings/stringprintf_unittest.cc
@@ -22,7 +22,10 @@
 static void StringAppendVTestHelper(std::string* out, const char* format, ...) {
   va_list ap;
   va_start(ap, format);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
   StringAppendV(out, format, ap);
+#pragma GCC diagnostic pop
   va_end(ap);
 }
 
diff --git a/third_party/get_gtest.sh b/third_party/get_gtest.sh
index 0a2e952..9b546ab 100755
--- a/third_party/get_gtest.sh
+++ b/third_party/get_gtest.sh
@@ -15,16 +15,17 @@
 
 # gtest is in process of changing of dir structure and it has broken build
 # files. So this is temporarily workaround to fix that.
-git reset --hard d945d8c000a0ade73585d143532266968339bbb3
+git reset --hard 82b11b8cfcca464c2ac74b623d04e74452e74f32
 mv googletest googlemock/gtest
 
-for SUB_DIR in googlemock/gtest googlemock; do
-  cd $THIRD_PARTY/googletest/$SUB_DIR || exit 1
-  autoreconf -fvi || exit 1
-  ./configure --disable-shared || exit 1
-  make || exit 1
-  cp -rf include/* $THIRD_PARTY/include/ || exit 1
-  cp -rf lib/.libs/* $THIRD_PARTY/lib/ || exit 1
-done
+cd $THIRD_PARTY/googletest/googlemock/gtest/make || exit 1
+make gtest.a || exit 1
+cp -rf ../include/* $THIRD_PARTY/include/ || exit 1
+cp -rf gtest.a $THIRD_PARTY/lib/ || exit 1
+
+cd $THIRD_PARTY/googletest/googlemock/make || exit 1
+make gmock.a || exit 1
+cp -rf ../include/* $THIRD_PARTY/include/ || exit 1
+cp -rf gmock.a $THIRD_PARTY/lib/ || exit 1
 
 rm -rf $THIRD_PARTY/googletest
diff --git a/third_party/third_party.mk b/third_party/third_party.mk
index c3e1cf0..8a11e2d 100644
--- a/third_party/third_party.mk
+++ b/third_party/third_party.mk
@@ -7,7 +7,7 @@
 
 third_party_chromium_base_obj_files := $(THIRD_PARTY_CHROMIUM_BASE_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
 
-$(third_party_chromium_base_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/gtest/gtest.h
+$(third_party_chromium_base_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
@@ -15,11 +15,11 @@
 
 $(third_party_chromium_base_unittest_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/gtest/gtest.h
 	mkdir -p $(dir $@)
-	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
+	$(CXX) $(DEFS_TEST) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
 third_party_chromium_crypto_obj_files := $(THIRD_PARTY_CHROMIUM_CRYPTO_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
 
-$(third_party_chromium_crypto_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/gtest/gtest.h
+$(third_party_chromium_crypto_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
@@ -27,7 +27,7 @@
 
 $(third_party_chromium_crypto_unittest_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/gtest/gtest.h
 	mkdir -p $(dir $@)
-	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
+	$(CXX) $(DEFS_TEST) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
 ###
 # third_party/modp_b64/
@@ -50,7 +50,10 @@
 ###
 # libgtest and libgmock (third_party, downloaded on build)
 
-third_party/include/gtest/gtest.h :
+third_party/lib/gtest.a: third_party/include/gtest/gtest.h
+third_party/lib/gmock.a: third_party/include/gtest/gtest.h
+
+third_party/include/gtest/gtest.h:
 	@echo Downloading and building libgtest and libgmock...
 	third_party/get_gtest.sh
 	@echo Finished downloading and building libgtest and libgmock.