all: update to new errors interface and update vendored repos to match

Change-Id: I8f0db92dd78bd74538619b4105273bbaf2f8a4a1
Reviewed-on: https://upspin-review.googlesource.com/16820
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/Gopkg.lock b/Gopkg.lock
index f4501e6..f36e90a 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -95,7 +95,7 @@
   branch = "master"
   name = "upspin.io"
   packages = ["access","bind","cache","client","client/clientutil","client/file","cloud/https","cloud/mail","cloud/mail/sendgrid","cloud/storage","config","dir/inprocess","dir/remote","dir/server","dir/server/serverlog","dir/server/tree","dir/unassigned","errors","factotum","flags","key/inprocess","key/remote","key/server","key/sha256key","key/transports","key/unassigned","key/usercache","log","metric","pack","pack/ee","pack/eeintegrity","pack/internal","pack/packutil","pack/plain","path","rpc","rpc/dirserver","rpc/keyserver","rpc/local","rpc/storeserver","serverutil","serverutil/dirserver","serverutil/frontend","serverutil/keyserver","serverutil/perm","serverutil/signup","serverutil/storeserver","serverutil/upspinserver","serverutil/web","shutdown","store/inprocess","store/remote","store/server","store/transports","store/unassigned","subcmd","test/testutil","transports","upspin","upspin/proto","user","valid","version"]
-  revision = "334666d02f3b336a67e541ad38ff942466a00d9f"
+  revision = "09c319761a94cb2fe53bbf74ec0e1cad45bc70da"
 
 [solve-meta]
   analyzer-name = "dep"
diff --git a/cloud/gcpmetric/metric.go b/cloud/gcpmetric/metric.go
index dece62b..a56438b 100644
--- a/cloud/gcpmetric/metric.go
+++ b/cloud/gcpmetric/metric.go
@@ -57,7 +57,7 @@
 // as labels on GCP. They are useful, for example, in the case of
 // differentiating a metric coming from a test instance versus production.
 func NewSaver(projectID string, n, maxQPS int, labels ...string) (metric.Saver, error) {
-	const op = "gcpmetric.New"
+	const op errors.Op = "gcpmetric.New"
 	// Authentication is provided by the gcloud tool when running locally, and
 	// by the associated service account when running on Compute Engine.
 	client, err := google.DefaultClient(context.Background(), trace.CloudPlatformScope)
@@ -73,7 +73,7 @@
 		return nil, errors.E(op, errors.IO, err)
 	}
 	if len(labels)%2 != 0 {
-		return nil, errors.E(op, errors.Invalid, errors.Str("metric labels must come in pairs"))
+		return nil, errors.E(op, errors.Invalid, "metric labels must come in pairs")
 	}
 
 	var rate *serverutil.RateLimiter
@@ -173,7 +173,7 @@
 		}
 		traceSpans[i] = &trace.TraceSpan{
 			SpanId:    uint64(i + 1),
-			Name:      s.Name,
+			Name:      string(s.Name),
 			StartTime: formatTime(s.StartTime),
 			EndTime:   formatTime(s.EndTime),
 			Kind:      toKindString(s.Kind),
diff --git a/cloud/storage/gcs/gcs.go b/cloud/storage/gcs/gcs.go
index eac3960..22c4ccf 100644
--- a/cloud/storage/gcs/gcs.go
+++ b/cloud/storage/gcs/gcs.go
@@ -60,7 +60,7 @@
 
 // New initializes a Storage implementation that stores data to Google Cloud Storage.
 func New(opts *storage.Opts) (storage.Storage, error) {
-	const op = "cloud/storage/gcs.New"
+	const op errors.Op = "cloud/storage/gcs.New"
 
 	bucket, ok := opts.Opts[bucketName]
 	if !ok {
@@ -122,7 +122,7 @@
 
 // Download implements Storage.
 func (gcs *gcsImpl) Download(ref string) ([]byte, error) {
-	const op = "cloud/storage/gcs.Download"
+	const op errors.Op = "cloud/storage/gcs.Download"
 	resp, err := gcs.service.Objects.Get(gcs.bucketName, ref).Download()
 	if err != nil {
 		if gcsErr, ok := err.(*googleapi.Error); ok && gcsErr.Code == 404 {
@@ -140,7 +140,7 @@
 
 // Put implements Storage.
 func (gcs *gcsImpl) Put(ref string, contents []byte) error {
-	const op = "cloud/storage/gcs.Put"
+	const op errors.Op = "cloud/storage/gcs.Put"
 	for tries := 0; ; tries++ {
 		_, err := gcs.service.Objects.Insert(gcs.bucketName, &gcsBE.Object{Name: ref}).
 			Media(bytes.NewReader(contents)).
diff --git a/cmd/hostserver-gcp/server.go b/cmd/hostserver-gcp/server.go
index 2271368..7cecd64 100644
--- a/cmd/hostserver-gcp/server.go
+++ b/cmd/hostserver-gcp/server.go
@@ -252,7 +252,7 @@
 	}
 	parts := strings.Split(p.FilePath(), "/")
 	if len(parts) != 2 {
-		return nil, errors.E(errors.Permission, de.Name, errors.Str("file names must be of the form user@example.com/ip"))
+		return nil, errors.E(errors.Permission, de.Name, "file names must be of the form user@example.com/ip")
 	}
 	user, ip := upspin.UserName(parts[0]), parts[1]
 	if user != s.user {
@@ -286,7 +286,7 @@
 
 // The DirServer and StoreServer methods below are not implemented.
 
-var errNotImplemented = errors.E(errors.Invalid, errors.Str("method not implemented"))
+var errNotImplemented = errors.E(errors.Invalid, "method not implemented")
 
 func (dirServer) Delete(name upspin.PathName) (*upspin.DirEntry, error) {
 	return nil, errNotImplemented
diff --git a/vendor/upspin.io/access/access.go b/vendor/upspin.io/access/access.go
index 9e10072..e30ec84 100644
--- a/vendor/upspin.io/access/access.go
+++ b/vendor/upspin.io/access/access.go
@@ -165,7 +165,7 @@
 
 // Parse parses the contents of the path name, in data, and returns the parsed Access.
 func Parse(pathName upspin.PathName, data []byte) (*Access, error) {
-	const op = "access.Parse"
+	const op errors.Op = "access.Parse"
 	a, parsed, err := newAccess(pathName)
 	if err != nil {
 		return nil, err
@@ -558,7 +558,7 @@
 // RemoveGroup undoes the installation of a group added by AddGroup.
 // It returns an error if the path is bad or the group is not present.
 func RemoveGroup(pathName upspin.PathName) error {
-	const op = "access.RemoveGroup"
+	const op errors.Op = "access.RemoveGroup"
 	parsed, err := path.Parse(pathName)
 	if err != nil {
 		return err
@@ -566,7 +566,7 @@
 	mu.Lock()
 	defer mu.Unlock()
 	if _, found := groups[parsed.Path()]; !found {
-		return errors.E(op, errors.NotExist, errors.Str("group does not exist"))
+		return errors.E(op, errors.NotExist, "group does not exist")
 	}
 	delete(groups, parsed.Path())
 	return nil
@@ -574,7 +574,7 @@
 
 // ParseGroup parses a group file but does not call AddGroup to install it.
 func ParseGroup(parsed path.Parsed, contents []byte) (group []path.Parsed, err error) {
-	const op = "access.ParseGroup"
+	const op errors.Op = "access.ParseGroup"
 	// Temporary. Pre-allocate so it can be reused in the loop, saving allocations.
 	users := make([][]byte, 10)
 	s := bufio.NewScanner(bytes.NewReader(contents))
@@ -902,7 +902,7 @@
 
 // MarshalJSON returns a JSON-encoded representation of this Access struct.
 func (a *Access) MarshalJSON() ([]byte, error) {
-	const op = "access.MarshalJSON"
+	const op errors.Op = "access.MarshalJSON"
 	// We need to export a field of Access but we don't want to make it public,
 	// so we encode it separately.
 	var buf bytes.Buffer
@@ -915,7 +915,7 @@
 
 // UnmarshalJSON returns an Access given its path name and its JSON encoding.
 func UnmarshalJSON(name upspin.PathName, jsonAccess []byte) (*Access, error) {
-	const op = "access.UnmarshalJSON"
+	const op errors.Op = "access.UnmarshalJSON"
 	var list [numRights][]path.Parsed
 	err := json.Unmarshal(jsonAccess, &list)
 	if err != nil {
diff --git a/vendor/upspin.io/bind/bind.go b/vendor/upspin.io/bind/bind.go
index 95155ea..23cb07c 100644
--- a/vendor/upspin.io/bind/bind.go
+++ b/vendor/upspin.io/bind/bind.go
@@ -100,7 +100,7 @@
 // the given user. If the name is empty, it returns the directory endpoint
 // in the config.
 func DirServerFor(cc upspin.Config, userName upspin.UserName) (upspin.DirServer, error) {
-	const op = "bind.DirServerFor"
+	const op errors.Op = "bind.DirServerFor"
 	if userName == "" {
 		// If name is empty just return the directory at cc.DirEndpoint().
 		d, err := DirServer(cc, cc.DirEndpoint())
@@ -137,7 +137,7 @@
 	if firstErr != nil {
 		return nil, errors.E(op, firstErr)
 	}
-	return nil, errors.E(op, userName, errors.Str("no directory endpoints found"))
+	return nil, errors.E(op, userName, "no directory endpoints found")
 
 }
 
@@ -176,12 +176,12 @@
 	return service, nil
 }
 
-func (s *servers) registerOp() string {
-	return "bind.Register" + s.kind + "Server" // "bind.RegisterKeyServer"
+func (s *servers) registerOp() errors.Op {
+	return errors.Op("bind.Register" + s.kind + "Server") // "bind.RegisterKeyServer"
 }
 
-func (s *servers) serverOp() string {
-	return "bind." + s.kind + "Server" // "bind.KeyServer"
+func (s *servers) serverOp() errors.Op {
+	return errors.Op("bind." + s.kind + "Server") // "bind.KeyServer"
 }
 
 // NoCache supresses the caching of dial results. This was added for
diff --git a/vendor/upspin.io/client/client.go b/vendor/upspin.io/client/client.go
index c44a12a..bfcf842 100644
--- a/vendor/upspin.io/client/client.go
+++ b/vendor/upspin.io/client/client.go
@@ -45,15 +45,15 @@
 
 // PutLink implements upspin.Client.
 func (c *Client) PutLink(oldName, linkName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "client.PutLink"
+	const op errors.Op = "client.PutLink"
 	m, s := newMetric(op)
 	defer m.Done()
 
 	if access.IsAccessControlFile(oldName) {
-		return nil, errors.E(op, oldName, errors.Invalid, errors.Str("cannot link to Access or Group file"))
+		return nil, errors.E(op, oldName, errors.Invalid, "cannot link to Access or Group file")
 	}
 	if access.IsAccessControlFile(linkName) {
-		return nil, errors.E(op, linkName, errors.Invalid, errors.Str("cannot create link named Access or Group"))
+		return nil, errors.E(op, linkName, errors.Invalid, "cannot create link named Access or Group")
 	}
 
 	parsed, err := path.Parse(oldName)
@@ -100,7 +100,7 @@
 
 // Put implements upspin.Client.
 func (c *Client) Put(name upspin.PathName, data []byte) (*upspin.DirEntry, error) {
-	const op = "client.Put"
+	const op errors.Op = "client.Put"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -215,7 +215,7 @@
 	if canWrite {
 		return nil
 	}
-	return errors.E(errors.Invalid, parsed.User(), errors.Str("signer does not have write permission"))
+	return errors.E(errors.Invalid, parsed.User(), "signer does not have write permission")
 }
 
 // access returns an Access struct for the applicable, parsed Access file.
@@ -302,7 +302,7 @@
 		return err
 	}
 	if !access.IsAccessFile(accessEntry.Name) {
-		return errors.E(errors.Internal, accessEntry.Name, errors.Str("not an Access file"))
+		return errors.E(errors.Internal, accessEntry.Name, "not an Access file")
 	}
 	accessPath, err := path.Parse(accessEntry.Name)
 	if err != nil {
@@ -317,7 +317,7 @@
 	// unpacks correctly, that validates the signing key is that of Writer.
 	// So, here we validate that Writer is parsedName.User().
 	if accessEntry.Writer != namePath.User() {
-		return errors.E(errors.Invalid, accessPath.Path(), namePath.User(), errors.Str("writer of Access file is not the user of the requested path"))
+		return errors.E(errors.Invalid, accessPath.Path(), namePath.User(), "writer of Access file is not the user of the requested path")
 	}
 	return nil
 }
@@ -326,7 +326,7 @@
 // This call, if successful, will replace entry.Name with the value, after any
 // link evaluation, from the final call to WhichAccess. The caller may then
 // use that name or entry to avoid evaluating the links again.
-func (c *Client) addReaders(op string, entry *upspin.DirEntry, packer upspin.Packer, readers []upspin.UserName) error {
+func (c *Client) addReaders(op errors.Op, entry *upspin.DirEntry, packer upspin.Packer, readers []upspin.UserName) error {
 	if packer.Packing() != upspin.EEPack {
 		return nil
 	}
@@ -337,7 +337,7 @@
 	readersPublicKey := make([]upspin.PublicKey, 0, len(readers)+2)
 	f := c.config.Factotum()
 	if f == nil {
-		return errors.E(op, name, errors.Permission, errors.Str("no factotum available"))
+		return errors.E(op, name, errors.Permission, "no factotum available")
 	}
 	readersPublicKey = append(readersPublicKey, f.PublicKey())
 	all := access.IsAccessControlFile(entry.Name)
@@ -374,7 +374,7 @@
 // according to the Access file.
 // If the Access file cannot be read because of lack of permissions,
 // it returns the owner of the file (but only if we are not the owner).
-func (c *Client) getReaders(op string, name upspin.PathName, accessEntry *upspin.DirEntry) ([]upspin.UserName, error) {
+func (c *Client) getReaders(op errors.Op, name upspin.PathName, accessEntry *upspin.DirEntry) ([]upspin.UserName, error) {
 	if accessEntry == nil {
 		// No Access file present, therefore we must be the owner.
 		return nil, nil
@@ -433,7 +433,7 @@
 
 // MakeDirectory implements upspin.Client.
 func (c *Client) MakeDirectory(name upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "client.MakeDirectory"
+	const op errors.Op = "client.MakeDirectory"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -451,7 +451,7 @@
 
 // Get implements upspin.Client.
 func (c *Client) Get(name upspin.PathName) ([]byte, error) {
-	const op = "client.Get"
+	const op errors.Op = "client.Get"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -491,7 +491,7 @@
 
 // Lookup implements upspin.Client.
 func (c *Client) Lookup(name upspin.PathName, followFinal bool) (*upspin.DirEntry, error) {
-	const op = "client.Lookup"
+	const op errors.Op = "client.Lookup"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -518,7 +518,7 @@
 // the operation followed by the argument to the last successful
 // call to fn, which for instance will contain the actual path that
 // resulted in a successful call to WhichAccess.
-func (c *Client) lookup(op string, entry *upspin.DirEntry, fn lookupFn, followFinal bool, s *metric.Span) (resultEntry, finalSuccessfulEntry *upspin.DirEntry, err error) {
+func (c *Client) lookup(op errors.Op, entry *upspin.DirEntry, fn lookupFn, followFinal bool, s *metric.Span) (resultEntry, finalSuccessfulEntry *upspin.DirEntry, err error) {
 	ss := s.StartSpan("lookup")
 	defer ss.End()
 
@@ -550,7 +550,7 @@
 		}
 		// Misbehaving servers could return a nil entry. Handle that explicitly. Issue 451.
 		if resultEntry == nil {
-			return nil, nil, errors.E(op, errors.Internal, prevEntry.Name, errors.Str("server returned nil entry for link"))
+			return nil, nil, errors.E(op, errors.Internal, prevEntry.Name, "server returned nil entry for link")
 		}
 		// We have a link.
 		// First, allocate a new entry if necessary so we don't overwrite user's memory.
@@ -567,7 +567,7 @@
 		resultPath := parsedResult.Path()
 		// The result entry's name must be a prefix of the name we're looking up.
 		if !strings.HasPrefix(parsed.String(), string(resultPath)) {
-			return nil, nil, errors.E(op, resultPath, errors.Internal, errors.Str("link path not prefix"))
+			return nil, nil, errors.E(op, resultPath, errors.Internal, "link path not prefix")
 		}
 		// Update the entry to have the new Name field.
 		if resultPath == parsed.Path() {
@@ -582,7 +582,7 @@
 			entry.Name = path.Join(resultEntry.Link, string(parsed.Path()[len(resultPath):]))
 		}
 	}
-	return nil, nil, errors.E(op, errors.IO, originalName, errors.Str("link loop"))
+	return nil, nil, errors.E(op, errors.IO, originalName, "link loop")
 }
 
 func deleteLookupFn(dir upspin.DirServer, entry *upspin.DirEntry, s *metric.Span) (*upspin.DirEntry, error) {
@@ -592,7 +592,7 @@
 
 // Delete implements upspin.Client.
 func (c *Client) Delete(name upspin.PathName) error {
-	const op = "client.Delete"
+	const op errors.Op = "client.Delete"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -602,7 +602,7 @@
 
 // Glob implements upspin.Client.
 func (c *Client) Glob(pattern string) ([]*upspin.DirEntry, error) {
-	const op = "client.Glob"
+	const op errors.Op = "client.Glob"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -652,7 +652,7 @@
 	}
 	if len(next) > 0 {
 		// TODO: Return partial results?
-		return nil, errors.E(op, upspin.PathName(pattern), errors.Str("link loop"))
+		return nil, errors.E(op, upspin.PathName(pattern), "link loop")
 	}
 	results = upspin.SortDirEntries(results, true)
 	return results, nil
@@ -699,13 +699,13 @@
 
 // Open implements upspin.Client.
 func (c *Client) Open(name upspin.PathName) (upspin.File, error) {
-	const op = "client.Open"
+	const op errors.Op = "client.Open"
 	entry, err := c.Lookup(name, followFinalLink)
 	if err != nil {
 		return nil, errors.E(op, err)
 	}
 	if entry.IsDir() {
-		return nil, errors.E(op, errors.IsDir, name, errors.Str("cannot Open a directory"))
+		return nil, errors.E(op, errors.IsDir, name, "cannot Open a directory")
 	}
 	if err = c.validSigner(entry); err != nil {
 		return nil, errors.E(op, name, err)
@@ -719,7 +719,7 @@
 
 // DirServer implements upspin.Client.
 func (c *Client) DirServer(name upspin.PathName) (upspin.DirServer, error) {
-	const op = "Client.DirServer"
+	const op errors.Op = "Client.DirServer"
 	parsed, err := path.Parse(name)
 	if err != nil {
 		return nil, errors.E(op, err)
@@ -734,7 +734,7 @@
 // PutDuplicate implements upspin.Client.
 // If one of the two files is later modified, the copy and the original will differ.
 func (c *Client) PutDuplicate(oldName, newName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "client.PutDuplicate"
+	const op errors.Op = "client.PutDuplicate"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -743,7 +743,7 @@
 
 // Rename implements upspin.Client.
 func (c *Client) Rename(oldName, newName upspin.PathName) error {
-	const op = "client.Rename"
+	const op errors.Op = "client.Rename"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -753,7 +753,7 @@
 
 // SetTime implements upspin.Client.
 func (c *Client) SetTime(name upspin.PathName, t upspin.Time) error {
-	const op = "client.SetTime"
+	const op errors.Op = "client.SetTime"
 	m, s := newMetric(op)
 	defer m.Done()
 
@@ -778,13 +778,13 @@
 	return nil
 }
 
-func (c *Client) dupOrRename(op string, oldName, newName upspin.PathName, rename bool, s *metric.Span) (*upspin.DirEntry, error) {
+func (c *Client) dupOrRename(op errors.Op, oldName, newName upspin.PathName, rename bool, s *metric.Span) (*upspin.DirEntry, error) {
 	entry, _, err := c.lookup(op, &upspin.DirEntry{Name: oldName}, lookupLookupFn, doNotFollowFinalLink, s)
 	if err != nil {
 		return nil, err
 	}
 	if entry.IsDir() {
-		return nil, errors.E(op, oldName, errors.IsDir, errors.Str("cannot link or rename directories"))
+		return nil, errors.E(op, oldName, errors.IsDir, "cannot link or rename directories")
 	}
 	trueOldName := entry.Name
 
@@ -793,7 +793,7 @@
 		return nil, errors.E(op, oldName, errors.Invalid, errors.Errorf("unrecognized Packing %d", c.config.Packing()))
 	}
 	if access.IsAccessControlFile(newName) {
-		return nil, errors.E(op, newName, errors.Invalid, errors.Str("Access or Group files cannot be renamed"))
+		return nil, errors.E(op, newName, errors.Invalid, "Access or Group files cannot be renamed")
 	}
 
 	// Update the directory entry with the new name and sequence.
@@ -846,7 +846,7 @@
 	return entry, nil
 }
 
-func newMetric(op string) (*metric.Metric, *metric.Span) {
+func newMetric(op errors.Op) (*metric.Metric, *metric.Span) {
 	m := metric.New("")
 	s := m.StartSpan(op).SetKind(metric.Client)
 	return m, s
diff --git a/vendor/upspin.io/client/clientutil/readall.go b/vendor/upspin.io/client/clientutil/readall.go
index 97f5f02..1558f2b 100644
--- a/vendor/upspin.io/client/clientutil/readall.go
+++ b/vendor/upspin.io/client/clientutil/readall.go
@@ -19,10 +19,10 @@
 // the necessary keys loaded in the config to unpack the cipher if the entry
 // is encrypted.
 func ReadAll(cfg upspin.Config, entry *upspin.DirEntry) ([]byte, error) {
-	const op = "client/clientutil.ReadAll"
+	const op errors.Op = "client/clientutil.ReadAll"
 
 	if entry.IsLink() {
-		return nil, errors.E(op, entry.Name, errors.Invalid, errors.Str("can't read a link entry"))
+		return nil, errors.E(op, entry.Name, errors.Invalid, "can't read a link entry")
 	}
 	if entry.IsIncomplete() {
 		return nil, errors.E(op, entry.Name, errors.Permission)
@@ -31,7 +31,7 @@
 		// Access files must be written by their owners only.
 		p, _ := path.Parse(entry.SignedName)
 		if p.User() != entry.Writer {
-			return nil, errors.E(errors.Invalid, p.User(), errors.Str("writer of Access file does not match owner"))
+			return nil, errors.E(errors.Invalid, p.User(), "writer of Access file does not match owner")
 		}
 	}
 
@@ -67,7 +67,7 @@
 // ReadLocation uses the provided Config to fetch the contents of the given
 // Location, following any StoreServer.Get redirects.
 func ReadLocation(cfg upspin.Config, loc upspin.Location) ([]byte, error) {
-	const op = "client/clientutil.ReadLocation"
+	const op errors.Op = "client/clientutil.ReadLocation"
 
 	// firstError remembers the first error we saw.
 	// If we fail completely we return it.
diff --git a/vendor/upspin.io/client/file/file.go b/vendor/upspin.io/client/file/file.go
index 356b266..5c55268 100644
--- a/vendor/upspin.io/client/file/file.go
+++ b/vendor/upspin.io/client/file/file.go
@@ -49,7 +49,7 @@
 // using the given Config.
 func Readable(cfg upspin.Config, entry *upspin.DirEntry) (*File, error) {
 	// TODO(adg): check if this is a dir or link?
-	const op = "client/file.Readable"
+	const op errors.Op = "client/file.Readable"
 
 	packer := pack.Lookup(entry.Packing)
 	if packer == nil {
@@ -93,7 +93,7 @@
 
 // Read implements upspin.File.
 func (f *File) Read(b []byte) (n int, err error) {
-	const op = "file.Read"
+	const op errors.Op = "file.Read"
 	n, err = f.readAt(op, b, f.offset)
 	if err == nil {
 		f.offset += int64(n)
@@ -103,19 +103,19 @@
 
 // ReadAt implements upspin.File.
 func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
-	const op = "file.ReadAt"
+	const op errors.Op = "file.ReadAt"
 	return f.readAt(op, b, off)
 }
 
-func (f *File) readAt(op string, dst []byte, off int64) (n int, err error) {
+func (f *File) readAt(op errors.Op, dst []byte, off int64) (n int, err error) {
 	if f.closed {
 		return 0, f.errClosed(op)
 	}
 	if f.writable {
-		return 0, errors.E(op, errors.Invalid, f.name, errors.Errorf("not open for read"))
+		return 0, errors.E(op, errors.Invalid, f.name, "not open for read")
 	}
 	if off < 0 {
-		return 0, errors.E(op, errors.Invalid, f.name, errors.Errorf("negative offset"))
+		return 0, errors.E(op, errors.Invalid, f.name, "negative offset")
 	}
 	if off > f.size {
 		return 0, errors.E(op, errors.Invalid, f.name, errors.Errorf("offset (%d) beyond end of file (%d)", off, f.size))
@@ -175,7 +175,7 @@
 
 // Seek implements upspin.File.
 func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
-	const op = "file.Seek"
+	const op errors.Op = "file.Seek"
 	if f.closed {
 		return 0, f.errClosed(op)
 	}
@@ -191,10 +191,10 @@
 			ret = f.size + offset
 		}
 	default:
-		return 0, errors.E(op, errors.Invalid, f.name, errors.Str("bad whence"))
+		return 0, errors.E(op, errors.Invalid, f.name, "bad whence")
 	}
 	if ret < 0 || offset > maxInt || !f.writable && ret > f.size {
-		return 0, errors.E(op, errors.Invalid, f.name, errors.Str("bad offset"))
+		return 0, errors.E(op, errors.Invalid, f.name, "bad offset")
 	}
 	f.offset = ret
 	return ret, nil
@@ -202,7 +202,7 @@
 
 // Write implements upspin.File.
 func (f *File) Write(b []byte) (n int, err error) {
-	const op = "file.Write"
+	const op errors.Op = "file.Write"
 	n, err = f.writeAt(op, b, f.offset)
 	if err == nil {
 		f.offset += int64(n)
@@ -212,23 +212,23 @@
 
 // WriteAt implements upspin.File.
 func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
-	const op = "file.WriteAt"
+	const op errors.Op = "file.WriteAt"
 	return f.writeAt(op, b, off)
 }
 
-func (f *File) writeAt(op string, b []byte, off int64) (n int, err error) {
+func (f *File) writeAt(op errors.Op, b []byte, off int64) (n int, err error) {
 	if f.closed {
 		return 0, f.errClosed(op)
 	}
 	if !f.writable {
-		return 0, errors.E(op, errors.Invalid, f.name, errors.Errorf("not open for write"))
+		return 0, errors.E(op, errors.Invalid, f.name, "not open for write")
 	}
 	if off < 0 {
-		return 0, errors.E(op, errors.Invalid, f.name, errors.Errorf("negative offset"))
+		return 0, errors.E(op, errors.Invalid, f.name, "negative offset")
 	}
 	end := off + int64(len(b))
 	if end > maxInt {
-		return 0, errors.E(op, errors.Invalid, f.name, errors.Errorf("file too long"))
+		return 0, errors.E(op, errors.Invalid, f.name, "file too long")
 	}
 	if end > int64(cap(f.data)) {
 		// Grow the capacity of f.data but keep length the same.
@@ -251,7 +251,7 @@
 
 // Close implements upspin.File.
 func (f *File) Close() error {
-	const op = "file.Close"
+	const op errors.Op = "file.Close"
 	if f.closed {
 		return f.errClosed(op)
 	}
@@ -269,6 +269,6 @@
 	return err
 }
 
-func (f *File) errClosed(op string) error {
-	return errors.E(op, errors.Invalid, f.name, errors.Str("is closed"))
+func (f *File) errClosed(op errors.Op) error {
+	return errors.E(op, errors.Invalid, f.name, "is closed")
 }
diff --git a/vendor/upspin.io/cloud/https/https.go b/vendor/upspin.io/cloud/https/https.go
index 9909f1a..b3997b5 100644
--- a/vendor/upspin.io/cloud/https/https.go
+++ b/vendor/upspin.io/cloud/https/https.go
@@ -229,7 +229,7 @@
 
 // newDefaultTLSConfig creates a new TLS config based on the certificate files given.
 func newDefaultTLSConfig(certFile string, certKeyFile string) (*tls.Config, error) {
-	const op = "cloud/https.newDefaultTLSConfig"
+	const op errors.Op = "cloud/https.newDefaultTLSConfig"
 	certReadable, err := isReadableFile(certFile)
 	if err != nil {
 		return nil, errors.E(op, errors.Invalid, errors.Errorf("SSL certificate in %q: %q", certFile, err))
diff --git a/vendor/upspin.io/cloud/mail/sendgrid/sendgrid.go b/vendor/upspin.io/cloud/mail/sendgrid/sendgrid.go
index 071df19..8c435e5 100644
--- a/vendor/upspin.io/cloud/mail/sendgrid/sendgrid.go
+++ b/vendor/upspin.io/cloud/mail/sendgrid/sendgrid.go
@@ -64,9 +64,9 @@
 
 // Send implements cloud/mail.Mail.
 func (s *sendgrid) Send(to, from, subject, text, html string) error {
-	const op = "cloud/mail/sendgrid.Send"
+	const op errors.Op = "cloud/mail/sendgrid.Send"
 	if text == "" && html == "" {
-		return errors.E(op, errors.Invalid, errors.Str("text or html body must be provided"))
+		return errors.E(op, errors.Invalid, "text or html body must be provided")
 	}
 	msg := message{
 		Personalizations: []personalizations{{
@@ -110,7 +110,7 @@
 		if err != nil {
 			return errors.E(op, errors.IO, err)
 		}
-		return errors.E(op, errors.IO, errors.Str(string(errStr)))
+		return errors.E(op, errors.IO, string(errStr))
 	}
 
 	return nil
diff --git a/vendor/upspin.io/cloud/storage/storage.go b/vendor/upspin.io/cloud/storage/storage.go
index e06335b..234f1c1 100644
--- a/vendor/upspin.io/cloud/storage/storage.go
+++ b/vendor/upspin.io/cloud/storage/storage.go
@@ -48,7 +48,7 @@
 
 // Register registers a new Storage under a name. It is typically used in init functions.
 func Register(name string, fn StorageConstructor) error {
-	const op = "cloud/storage.Register"
+	const op errors.Op = "cloud/storage.Register"
 	if _, exists := registration[name]; exists {
 		return errors.E(op, errors.Exist)
 	}
@@ -60,7 +60,7 @@
 // are specific to each storage backend. Neither key nor value may contain the characters "," or "=".
 // Use WithKeyValue repeatedly if these characters need to be used.
 func WithOptions(options string) DialOpts {
-	const op = "cloud/storage.WithOptions"
+	const op errors.Op = "cloud/storage.WithOptions"
 	return func(o *Opts) error {
 		pairs := strings.Split(options, ",")
 		for _, p := range pairs {
@@ -84,7 +84,7 @@
 
 // Dial dials the named storage backend using the dial options opts.
 func Dial(name string, opts ...DialOpts) (Storage, error) {
-	const op = "cloud/storage.Dial"
+	const op errors.Op = "cloud/storage.Dial"
 	fn, found := registration[name]
 	if !found {
 		return nil, errors.E(op, errors.Invalid, errors.Errorf("unknown storage backend type %q", name))
diff --git a/vendor/upspin.io/config/initconfig.go b/vendor/upspin.io/config/initconfig.go
index b777002..98b002b 100644
--- a/vendor/upspin.io/config/initconfig.go
+++ b/vendor/upspin.io/config/initconfig.go
@@ -83,7 +83,7 @@
 		}
 	}
 	if err != nil {
-		const op = "config.FromFile"
+		const op errors.Op = "config.FromFile"
 		if os.IsNotExist(err) {
 			return nil, errors.E(op, errors.NotExist, err)
 		}
@@ -127,7 +127,7 @@
 // The default value for tlscerts is the empty string,
 // in which case just the system roots are used.
 func InitConfig(r io.Reader) (upspin.Config, error) {
-	const op = "config.InitConfig"
+	const op errors.Op = "config.InitConfig"
 	vals := map[string]string{
 		username:    string(defaultUserName),
 		packing:     defaultPacking.String(),
@@ -259,7 +259,7 @@
 	return "", errors.E(errors.Invalid, errors.Errorf("unrecognized value %T", v))
 }
 
-func parseEndpoint(op string, vals map[string]string, key string, errorp *error) upspin.Endpoint {
+func parseEndpoint(op errors.Op, vals map[string]string, key string, errorp *error) upspin.Endpoint {
 	text, ok := vals[key]
 	if !ok || text == "" {
 		return upspin.Endpoint{}
@@ -437,7 +437,7 @@
 // SetFlagValues updates any flag that is still at its default value.
 // It will apply all the flags possible and return the last error seen.
 func SetFlagValues(cfg upspin.Config, cmd string) error {
-	const op = "config.SetFlagValues"
+	const op errors.Op = "config.SetFlagValues"
 	flagYAML := cfg.Value("cmdflags")
 	if flagYAML == "" {
 		return nil
@@ -491,7 +491,7 @@
 	}
 	h := u.HomeDir
 	if h == "" {
-		return "", errors.E(errors.NotExist, errors.Str("user home directory not found"))
+		return "", errors.E(errors.NotExist, "user home directory not found")
 	}
 	if err := isDir(h); err != nil {
 		return "", err
@@ -536,7 +536,7 @@
 		return errors.E(errors.IO, err)
 	}
 	if !fi.IsDir() {
-		return errors.E(errors.NotDir, errors.Str(p))
+		return errors.E(errors.NotDir, p)
 	}
 	return nil
 }
diff --git a/vendor/upspin.io/dir/inprocess/directory.go b/vendor/upspin.io/dir/inprocess/directory.go
index 76df827..eca19f6 100644
--- a/vendor/upspin.io/dir/inprocess/directory.go
+++ b/vendor/upspin.io/dir/inprocess/directory.go
@@ -163,7 +163,7 @@
 // makeRoot creates a new user root.
 // s.db is locked.
 func (s *server) makeRoot(parsed path.Parsed) (*upspin.DirEntry, error) {
-	const op = "dir/inprocess.makeRoot"
+	const op errors.Op = "dir/inprocess.makeRoot"
 	// Creating a root: easy!
 	// Only the owner can create the root, but the canPut check is sufficient since a
 	// non-existent root has no Access file yet.
@@ -186,7 +186,7 @@
 	// Copy the argument because we don't want to overwrite fields such as Sequence in caller.
 	entry := new(upspin.DirEntry)
 	*entry = *argEntry
-	const op = "dir/inprocess.Put"
+	const op errors.Op = "dir/inprocess.Put"
 	if err := valid.DirEntry(entry); err != nil {
 		return nil, errors.E(op, err)
 	}
@@ -206,7 +206,7 @@
 	if isAccess || isGroup {
 		if isAccess && entry.IsDir() {
 			// A Group file may be in a subdirectory; it's only Access files we worry about.
-			return nil, errors.E(op, entry.Name, errors.Invalid, errors.Str("cannot create a directory named Access"))
+			return nil, errors.E(op, entry.Name, errors.Invalid, "cannot create a directory named Access")
 		}
 		if !entry.IsDir() {
 			packer := pack.Lookup(entry.Packing)
@@ -218,11 +218,11 @@
 				return nil, errors.E(op, entry.Name, err)
 			}
 			if !ok {
-				return nil, errors.E(op, entry.Name, errors.Str("Access or Group files must be readable by access.AllUsers"))
+				return nil, errors.E(op, entry.Name, "Access or Group files must be readable by access.AllUsers")
 			}
 		}
 		if entry.IsLink() {
-			return nil, errors.E(op, entry.Name, errors.Str("cannot create a link named Access or Group"))
+			return nil, errors.E(op, entry.Name, "cannot create a link named Access or Group")
 		}
 		if isGroup {
 			// Check that the name is a legal Group name.
@@ -268,7 +268,7 @@
 // It may return ErrFollowLink.
 // s.db.mu must not be held, which means races are possible
 // but they are not harmful (are they?).
-func (s *server) canPut(op string, parsed path.Parsed, makeDirectory bool) (*upspin.DirEntry, error) {
+func (s *server) canPut(op errors.Op, parsed path.Parsed, makeDirectory bool) (*upspin.DirEntry, error) {
 	name := parsed.Path()
 	if makeDirectory && parsed.IsRoot() {
 		// We're fine.
@@ -320,16 +320,16 @@
 
 // put is the underlying implementation of Put, including making links and directories..
 // If deleting, we expect the entry to already be present and skip it on the rewrite.
-func (s *server) put(op string, entry *upspin.DirEntry, parsed path.Parsed, deleting bool) (*upspin.DirEntry, error) {
+func (s *server) put(op errors.Op, entry *upspin.DirEntry, parsed path.Parsed, deleting bool) (*upspin.DirEntry, error) {
 	pathName := parsed.Path()
 	if parsed.IsRoot() {
 		// Should not be here.
-		return nil, errors.E(op, pathName, errors.Internal, errors.Str("cannot create root with s.put"))
+		return nil, errors.E(op, pathName, errors.Internal, "cannot create root with s.put")
 	}
 	rootEntry, ok := s.db.root[parsed.User()]
 	if !ok {
 		// Cannot create user root with Put.
-		return nil, errors.E(op, upspin.PathName(parsed.User()), errors.Str("no such user root"))
+		return nil, errors.E(op, upspin.PathName(parsed.User()), "no such user root")
 	}
 	// Iterate along the path up to but not past the last element.
 	// We remember the entries as we descend for fast(er) overwrite of the Merkle tree.
@@ -377,13 +377,13 @@
 	s.db.root[parsed.User()] = rootEntry
 	if access.IsGroupFile(entry.Name) {
 		if entry.IsLink() {
-			return nil, errors.E(op, errors.Internal, entry.Name, errors.Str("Group file cannot be a link"))
+			return nil, errors.E(op, errors.Internal, entry.Name, "Group file cannot be a link")
 		}
 		// Group files are loaded on demand but we must wipe the cache.
 		access.RemoveGroup(entry.Name)
 	} else if access.IsAccessFile(entry.Name) {
 		if entry.IsLink() {
-			return nil, errors.E(op, errors.Internal, entry.Name, errors.Str("Access file cannot be a link"))
+			return nil, errors.E(op, errors.Internal, entry.Name, "Access file cannot be a link")
 		}
 		var accessFile *access.Access
 		if !deleting {
@@ -406,7 +406,7 @@
 
 // WhichAccess implements upspin.DirServer.WhichAccess.
 func (s *server) WhichAccess(pathName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/inprocess.WhichAccess"
+	const op errors.Op = "dir/inprocess.WhichAccess"
 	parsed, err := path.Parse(pathName)
 	if err != nil {
 		return nil, errors.E(op, err)
@@ -470,7 +470,7 @@
 
 // Watch implements upspin.DirServer.Watch.
 func (s *server) Watch(name upspin.PathName, seq int64, done <-chan struct{}) (<-chan upspin.Event, error) {
-	const op = "dir/inprocess.Watch"
+	const op errors.Op = "dir/inprocess.Watch"
 	parsed, err := path.Parse(name)
 	if err != nil {
 		return nil, errors.E(op, err)
@@ -491,7 +491,7 @@
 
 // Delete implements upspin.DirServer.Delete.
 func (s *server) Delete(pathName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/inprocess.Delete"
+	const op errors.Op = "dir/inprocess.Delete"
 	parsed, err := path.Parse(pathName)
 	if err != nil {
 		return nil, errors.E(op, err)
@@ -533,7 +533,7 @@
 	return entry, err
 }
 
-func (s *server) isEmptyDirectory(op string, entry *upspin.DirEntry) bool {
+func (s *server) isEmptyDirectory(op errors.Op, entry *upspin.DirEntry) bool {
 	if !entry.IsDir() {
 		return false
 	}
@@ -546,7 +546,7 @@
 
 // Lookup implements upspin.DirServer.Lookup.
 func (s *server) Lookup(pathName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/inprocess.Lookup"
+	const op errors.Op = "dir/inprocess.Lookup"
 	log.Debug.Println("Lookup", pathName)
 	parsed, err := path.Parse(pathName)
 	if err != nil {
@@ -584,7 +584,7 @@
 }
 
 // lookup is the internal version of lookup; it does not do any Access checks.
-func (s *server) lookup(op string, parsed path.Parsed, followFinal bool) (*upspin.DirEntry, error) {
+func (s *server) lookup(op errors.Op, parsed path.Parsed, followFinal bool) (*upspin.DirEntry, error) {
 	s.db.mu.RLock()
 	defer s.db.mu.RUnlock()
 	dirEntry, ok := s.db.root[parsed.User()]
@@ -623,7 +623,7 @@
 
 // Glob implements upspin.DirServer.Glob.
 func (s *server) Glob(pattern string) ([]*upspin.DirEntry, error) {
-	const op = "dir/inprocess.Glob"
+	const op errors.Op = "dir/inprocess.Glob"
 	log.Debug.Print(pattern)
 
 	entries, err := serverutil.Glob(pattern, s.Lookup, s.listDir)
@@ -636,7 +636,7 @@
 // listDir implements serverutil.ListFunc.
 // dirName should always be a directory.
 func (s *server) listDir(dirName upspin.PathName) ([]*upspin.DirEntry, error) {
-	const op = "dir/inprocess.Glob" // The only (indirect) caller of this function.
+	const op errors.Op = "dir/inprocess.Glob" // The only (indirect) caller of this function.
 	log.Debug.Println("listDir", dirName)
 
 	parsed, err := path.Parse(dirName)
@@ -704,7 +704,7 @@
 // given path, and if so returns a Permission error.
 // Otherwise it returns a Private error.
 // This is used to prevent probing of the name space.
-func (s *server) errPerm(op string, parsed path.Parsed) error {
+func (s *server) errPerm(op errors.Op, parsed path.Parsed) error {
 	canKnow, err := s.can(access.AnyRight, parsed)
 	if err != nil {
 		return errors.E(op, parsed.Path(), err)
@@ -721,7 +721,7 @@
 // has any right to the given entry, and if so returns the entry
 // and ErrFollowLink. If the use has no rights, it returns a
 // Private error.
-func (s *server) errLink(op string, entry *upspin.DirEntry, errArg error) (*upspin.DirEntry, error) {
+func (s *server) errLink(op errors.Op, entry *upspin.DirEntry, errArg error) (*upspin.DirEntry, error) {
 	if errArg != upspin.ErrFollowLink {
 		return entry, errArg
 	}
@@ -772,7 +772,7 @@
 
 // fetchEntry returns the reference for the named elem within the directory referenced by dirEntry.
 // It reads the whole directory, so avoid calling it repeatedly.
-func (s *server) fetchEntry(op string, entry *upspin.DirEntry, elem string) (*upspin.DirEntry, error) {
+func (s *server) fetchEntry(op errors.Op, entry *upspin.DirEntry, elem string) (*upspin.DirEntry, error) {
 	payload, err := s.readAll(entry)
 	if err != nil {
 		return nil, err
@@ -782,9 +782,9 @@
 
 // dirEntLookup returns the ref for the entry in the named directory whose contents are given in the payload.
 // The boolean is true if the entry itself describes a directory.
-func (s *server) dirEntLookup(op string, pathName upspin.PathName, payload []byte, elem string) (*upspin.DirEntry, error) {
+func (s *server) dirEntLookup(op errors.Op, pathName upspin.PathName, payload []byte, elem string) (*upspin.DirEntry, error) {
 	if len(elem) == 0 {
-		return nil, errors.E(op, pathName, errors.Str("empty path name element"))
+		return nil, errors.E(op, pathName, "empty path name element")
 	}
 	fileName := path.Join(pathName, elem)
 	var entry upspin.DirEntry
@@ -807,7 +807,7 @@
 
 // installEntry installs the new entry in the directory referenced by the dirEntry, appending or overwriting the
 // entry as required. It returns the entry of the updated directory and the blob itself.
-func (s *server) installEntry(op string, dirName upspin.PathName, dirEntry *upspin.DirEntry, newEntry *upspin.DirEntry, deleting, dirOverwriteOK bool) (*upspin.DirEntry, []byte, error) {
+func (s *server) installEntry(op errors.Op, dirName upspin.PathName, dirEntry *upspin.DirEntry, newEntry *upspin.DirEntry, deleting, dirOverwriteOK bool) (*upspin.DirEntry, []byte, error) {
 	dirData, err := s.readAll(dirEntry)
 	if err != nil {
 		return nil, nil, err
@@ -839,7 +839,7 @@
 			}
 			// If it's already there and is not expected to be a directory, this is an error.
 			if nextEntry.IsDir() && !dirOverwriteOK {
-				return nil, nil, errors.E(op, errors.IsDir, dirName, errors.Str("cannot overwrite directory"))
+				return nil, nil, errors.E(op, errors.IsDir, dirName, "cannot overwrite directory")
 			}
 		}
 		// Drop this entry so we can append the updated one (or skip it, if we're deleting).
@@ -873,7 +873,7 @@
 		if !found {
 			// The provided sequence number may be only SeqNotExist or SeqIgnore.
 			if newEntry.Sequence != upspin.SeqNotExist && newEntry.Sequence != upspin.SeqIgnore {
-				return nil, nil, errors.E(op, parsed.Path(), errors.Invalid, errors.Str("invalid sequence number"))
+				return nil, nil, errors.E(op, parsed.Path(), errors.Invalid, "invalid sequence number")
 			}
 		}
 		// Add new entry to directory.
@@ -897,9 +897,9 @@
 // running in the address space. It ignores the address within the endpoint but
 // requires that the transport be InProcess.
 func (s *server) Dial(config upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "dir/inprocess.Dial"
+	const op errors.Op = "dir/inprocess.Dial"
 	if e.Transport != upspin.InProcess {
-		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, errors.E(op, errors.Invalid, "unrecognized transport")
 	}
 	this := *s // Make a copy.
 	this.config = config
diff --git a/vendor/upspin.io/dir/inprocess/watch.go b/vendor/upspin.io/dir/inprocess/watch.go
index 409188b..61a5b54 100644
--- a/vendor/upspin.io/dir/inprocess/watch.go
+++ b/vendor/upspin.io/dir/inprocess/watch.go
@@ -85,7 +85,7 @@
 // If it returns false, it attempts to send an error event unless the
 // problem was an unresponsive client.
 func (l *listener) sendTree(name upspin.PathName) bool {
-	const op = "dir/inprocess.Watch"
+	const op errors.Op = "dir/inprocess.Watch"
 	parsed, err := path.Parse(name)
 	if err != nil {
 		// Shouldn't happen.
@@ -227,7 +227,7 @@
 
 // watch is the implementation of DirServer.Watch after basic checking is done.
 func (e *eventManager) watch(server *server, root path.Parsed, sequence int64, done <-chan struct{}) (<-chan upspin.Event, error) {
-	const op = "dir/inprocess.Watch"
+	const op errors.Op = "dir/inprocess.Watch"
 	events := make(chan upspin.Event, 10)
 	l := &listener{
 		eventMgr: e,
@@ -245,7 +245,7 @@
 	// The special case of an invalid sequence is returned as an event with an "invalid" error.
 	if sequence != 0 && sequence != -1 {
 		if sequence < 0 || int64(len(eventsSoFar)) < sequence {
-			events <- upspin.Event{Error: errors.E(op, errors.Invalid, errors.Str("bad sequence"))}
+			events <- upspin.Event{Error: errors.E(op, errors.Invalid, "bad sequence")}
 			close(events)
 			return events, nil
 		}
diff --git a/vendor/upspin.io/dir/remote/remote.go b/vendor/upspin.io/dir/remote/remote.go
index 002a550..35453f8 100644
--- a/vendor/upspin.io/dir/remote/remote.go
+++ b/vendor/upspin.io/dir/remote/remote.go
@@ -208,7 +208,7 @@
 	op := r.opf("Dial", "%q, %q", config.UserName(), e)
 
 	if e.Transport != upspin.Remote {
-		return nil, op.error(errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, op.error(errors.Invalid, "unrecognized transport")
 	}
 
 	// First try a cache
@@ -256,13 +256,13 @@
 func (r *remote) opf(method string, format string, args ...interface{}) *operation {
 	ep := r.cfg.endpoint.String()
 	s := fmt.Sprintf("dir/remote: %q: dir.%s", ep, method)
-	op := &operation{s, fmt.Sprintf(format, args...)}
+	op := &operation{errors.Op(s), fmt.Sprintf(format, args...)}
 	log.Debug.Print(op)
 	return op
 }
 
 type operation struct {
-	op   string
+	op   errors.Op
 	args string
 }
 
diff --git a/vendor/upspin.io/dir/server/access.go b/vendor/upspin.io/dir/server/access.go
index 27fdd72..12e6b8e 100644
--- a/vendor/upspin.io/dir/server/access.go
+++ b/vendor/upspin.io/dir/server/access.go
@@ -146,7 +146,7 @@
 	if firstErr != nil {
 		return nil, firstErr
 	}
-	return nil, errors.E(errors.NotExist, p.Path(), errors.Str("no remote entry for path"))
+	return nil, errors.E(errors.NotExist, p.Path(), "no remote entry for path")
 }
 
 // hasRight reports whether the current user has the given right on the path. If
@@ -218,7 +218,7 @@
 
 	// Sanity check: is this really an Access file?
 	if !access.IsAccessFile(entry.Name) {
-		return nil, errors.E(errors.Internal, entry.Name, errors.Str("not an Access file"))
+		return nil, errors.E(errors.Internal, entry.Name, "not an Access file")
 	}
 
 	// Is it in the cache?
@@ -228,7 +228,7 @@
 		var ok bool
 		accEntry, ok = a.(*accessEntry)
 		if !ok {
-			return nil, errors.E(errors.Internal, errors.Str("invalid accessEntry"))
+			return nil, errors.E(errors.Internal, "invalid accessEntry")
 		}
 		if entry.Sequence == accEntry.sequence {
 			return accEntry.acc, nil
@@ -265,7 +265,7 @@
 		var ok bool
 		acc, ok = cacheEntry.(*access.Access)
 		if !ok {
-			return nil, errors.E(errors.Internal, errors.Str("not an Access file"))
+			return nil, errors.E(errors.Internal, "not an Access file")
 		}
 	}
 	return
diff --git a/vendor/upspin.io/dir/server/server.go b/vendor/upspin.io/dir/server/server.go
index 3c6af8a..284d2a8 100644
--- a/vendor/upspin.io/dir/server/server.go
+++ b/vendor/upspin.io/dir/server/server.go
@@ -122,24 +122,24 @@
 
 // New creates a new instance of DirServer with the given options
 func New(cfg upspin.Config, options ...string) (upspin.DirServer, error) {
-	const op = "dir/server.New"
+	const op errors.Op = "dir/server.New"
 	if cfg == nil {
-		return nil, errors.E(op, errors.Invalid, errors.Str("nil config"))
+		return nil, errors.E(op, errors.Invalid, "nil config")
 	}
 	if cfg.DirEndpoint().Transport == upspin.Unassigned {
-		return nil, errors.E(op, errors.Invalid, errors.Str("directory endpoint cannot be unassigned"))
+		return nil, errors.E(op, errors.Invalid, "directory endpoint cannot be unassigned")
 	}
 	if cfg.KeyEndpoint().Transport == upspin.Unassigned {
-		return nil, errors.E(op, errors.Invalid, errors.Str("key endpoint cannot be unassigned"))
+		return nil, errors.E(op, errors.Invalid, "key endpoint cannot be unassigned")
 	}
 	if cfg.StoreEndpoint().Transport == upspin.Unassigned {
-		return nil, errors.E(op, errors.Invalid, errors.Str("store endpoint cannot be unassigned"))
+		return nil, errors.E(op, errors.Invalid, "store endpoint cannot be unassigned")
 	}
 	if cfg.UserName() == "" {
-		return nil, errors.E(op, errors.Invalid, errors.Str("empty user name"))
+		return nil, errors.E(op, errors.Invalid, "empty user name")
 	}
 	if cfg.Factotum() == nil {
-		return nil, errors.E(op, errors.Invalid, errors.Str("nil factotum"))
+		return nil, errors.E(op, errors.Invalid, "nil factotum")
 	}
 	// Check which options are present and pick suitable defaults.
 	var (
@@ -205,13 +205,13 @@
 
 // Lookup implements upspin.DirServer.
 func (s *server) Lookup(name upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/server.Lookup"
+	const op errors.Op = "dir/server.Lookup"
 	o, m := newOptMetric(op)
 	defer m.Done()
 	return s.lookupWithPermissions(op, name, o)
 }
 
-func (s *server) lookupWithPermissions(op string, name upspin.PathName, opts ...options) (*upspin.DirEntry, error) {
+func (s *server) lookupWithPermissions(op errors.Op, name upspin.PathName, opts ...options) (*upspin.DirEntry, error) {
 	p, err := path.Parse(name)
 	if err != nil {
 		return nil, errors.E(op, name, err)
@@ -238,7 +238,7 @@
 	// Check for Read access permission.
 	canRead, _, err := s.hasRight(access.Read, p, opts...)
 	if err == upspin.ErrFollowLink {
-		return nil, errors.E(op, errors.Internal, p.Path(), errors.Str("can't be link at this point"))
+		return nil, errors.E(op, errors.Internal, p.Path(), "can't be link at this point")
 	}
 	if err != nil {
 		return nil, errors.E(op, err)
@@ -285,7 +285,7 @@
 			return nil, err
 		}
 		if dirty {
-			return nil, errors.E(errors.Internal, errors.Str("flush didn't clean entry"))
+			return nil, errors.E(errors.Internal, "flush didn't clean entry")
 		}
 	}
 	if entry.IsLink() {
@@ -296,7 +296,7 @@
 
 // Put implements upspin.DirServer.
 func (s *server) Put(entry *upspin.DirEntry) (*upspin.DirEntry, error) {
-	const op = "dir/server.Put"
+	const op errors.Op = "dir/server.Put"
 	o, m := newOptMetric(op)
 	defer m.Done()
 
@@ -332,12 +332,12 @@
 	// Links can't be named Access or Group.
 	if isLink {
 		if isAccess || isGroup {
-			return nil, errors.E(op, p.Path(), errors.Invalid, errors.Str("link cannot be named Access or Group"))
+			return nil, errors.E(op, p.Path(), errors.Invalid, "link cannot be named Access or Group")
 		}
 	}
 	// Directories cannot have reserved names.
 	if isAccess && entry.IsDir() {
-		return nil, errors.E(op, errors.Invalid, entry.Name, errors.Str("cannot make directory named Access"))
+		return nil, errors.E(op, errors.Invalid, entry.Name, "cannot make directory named Access")
 	}
 
 	// Special files must use integrity pack (plain text + signature).
@@ -352,7 +352,7 @@
 			return nil, errors.E(op, err)
 		}
 		if !ok {
-			return nil, errors.E(op, p.Path(), errors.Str("Access or Group files must be readable by all"))
+			return nil, errors.E(op, p.Path(), "Access or Group files must be readable by all")
 		}
 	}
 
@@ -389,7 +389,7 @@
 		// OK; entry not found as expected. Can we create it?
 		canCreate, _, err := s.hasRight(access.Create, p, o)
 		if err == upspin.ErrFollowLink {
-			return nil, errors.E(op, p.Path(), errors.Internal, errors.Str("unexpected ErrFollowLink"))
+			return nil, errors.E(op, p.Path(), errors.Internal, "unexpected ErrFollowLink")
 		}
 		if err != nil {
 			return nil, errors.E(op, err)
@@ -400,7 +400,7 @@
 
 		// The provided sequence number for a new item may be only SeqNotExist or SeqIgnore.
 		if entry.Sequence != upspin.SeqNotExist && entry.Sequence != upspin.SeqIgnore {
-			return nil, errors.E(op, p.Path(), errors.Invalid, errors.Str("invalid sequence number"))
+			return nil, errors.E(op, p.Path(), errors.Invalid, "invalid sequence number")
 		}
 	} else if err != nil {
 		// Some unexpected error happened looking up path. Abort.
@@ -413,15 +413,15 @@
 		}
 		// Check if we can overwrite.
 		if existingEntry.IsDir() {
-			return nil, errors.E(op, p.Path(), errors.Exist, errors.Str("can't overwrite directory"))
+			return nil, errors.E(op, p.Path(), errors.Exist, "can't overwrite directory")
 		}
 		if entry.IsDir() {
-			return nil, errors.E(op, p.Path(), errors.Exist, errors.Str("can't overwrite file with directory"))
+			return nil, errors.E(op, p.Path(), errors.Exist, "can't overwrite file with directory")
 		}
 		// To overwrite a file, we need Write permission.
 		canWrite, _, err := s.hasRight(access.Write, p, o)
 		if err == upspin.ErrFollowLink {
-			return nil, errors.E(op, p.Path(), errors.Internal, errors.Str("unexpected ErrFollowLink"))
+			return nil, errors.E(op, p.Path(), errors.Internal, "unexpected ErrFollowLink")
 		}
 		if err != nil {
 			return nil, errors.E(op, err)
@@ -436,7 +436,7 @@
 		// We also must have the correct sequence number or SeqIgnore.
 		if entry.Sequence != upspin.SeqIgnore {
 			if entry.Sequence != existingEntry.Sequence {
-				return nil, errors.E(op, entry.Name, errors.Invalid, errors.Str("sequence number"))
+				return nil, errors.E(op, entry.Name, errors.Invalid, "sequence number")
 			}
 		}
 
@@ -469,7 +469,7 @@
 }
 
 // put performs Put on the user's tree.
-func (s *server) put(op string, p path.Parsed, entry *upspin.DirEntry, opts ...options) (*upspin.DirEntry, error) {
+func (s *server) put(op errors.Op, p path.Parsed, entry *upspin.DirEntry, opts ...options) (*upspin.DirEntry, error) {
 	o, ss := subspan("put", opts)
 	defer ss.End()
 
@@ -490,20 +490,20 @@
 
 // Glob implements upspin.DirServer.
 func (s *server) Glob(pattern string) ([]*upspin.DirEntry, error) {
-	const op = "dir/server.Glob"
+	const op errors.Op = "dir/server.Glob"
 	o, m := newOptMetric(op)
 	defer m.Done()
 
 	// lookup implements serverutil.LookupFunc. It checks permissions.
 	lookup := func(name upspin.PathName) (*upspin.DirEntry, error) {
-		const op = "dir/server.Lookup"
+		const op errors.Op = "dir/server.Lookup"
 		o, ss := subspan(op, []options{o})
 		defer ss.End()
 		return s.lookupWithPermissions(op, name, o)
 	}
 	// lookup implements serverutil.ListFunc. It checks permissions.
 	listDir := func(dirName upspin.PathName) ([]*upspin.DirEntry, error) {
-		const op = "dir/server.listDir"
+		const op errors.Op = "dir/server.listDir"
 		o, ss := subspan(op, []options{o})
 		defer ss.End()
 		return s.listDir(op, dirName, o)
@@ -518,7 +518,7 @@
 
 // listDir implements serverutil.ListFunc, with an additional options variadic.
 // dirName should always be a directory. It checks permissions.
-func (s *server) listDir(op string, dirName upspin.PathName, opts ...options) ([]*upspin.DirEntry, error) {
+func (s *server) listDir(op errors.Op, dirName upspin.PathName, opts ...options) ([]*upspin.DirEntry, error) {
 	parsed, err := path.Parse(dirName)
 	if err != nil {
 		return nil, errors.E(op, err)
@@ -579,7 +579,7 @@
 
 // Delete implements upspin.DirServer.
 func (s *server) Delete(name upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/server.Delete"
+	const op errors.Op = "dir/server.Delete"
 	o, m := newOptMetric(op)
 	defer m.Done()
 
@@ -639,7 +639,7 @@
 
 // WhichAccess implements upspin.DirServer.
 func (s *server) WhichAccess(name upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/server.WhichAccess"
+	const op errors.Op = "dir/server.WhichAccess"
 	o, m := newOptMetric(op)
 	defer m.Done()
 
@@ -665,7 +665,7 @@
 
 // Watch implements upspin.DirServer.Watch.
 func (s *server) Watch(name upspin.PathName, sequence int64, done <-chan struct{}) (<-chan upspin.Event, error) {
-	const op = "dir/server.Watch"
+	const op errors.Op = "dir/server.Watch"
 	o, m := newOptMetric(op)
 	defer m.Done()
 
@@ -701,7 +701,7 @@
 // watcher runs in a goroutine reading events from the tree and passing them
 // along to the original caller, but first verifying whether the user has rights
 // to know about the event.
-func (s *server) watch(op string, treeEvents <-chan *upspin.Event, outEvents chan<- upspin.Event) {
+func (s *server) watch(op errors.Op, treeEvents <-chan *upspin.Event, outEvents chan<- upspin.Event) {
 	const sendTimeout = time.Minute
 
 	t := time.NewTimer(sendTimeout)
@@ -770,9 +770,9 @@
 
 // Dial implements upspin.Dialer.
 func (s *server) Dial(ctx upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "dir/server.Dial"
+	const op errors.Op = "dir/server.Dial"
 	if e.Transport == upspin.Unassigned {
-		return nil, errors.E(op, errors.Invalid, errors.Str("transport must not be unassigned"))
+		return nil, errors.E(op, errors.Invalid, "transport must not be unassigned")
 	}
 	if err := valid.UserName(ctx.UserName()); err != nil {
 		return nil, errors.E(op, errors.Invalid, err)
@@ -804,7 +804,7 @@
 
 // Close implements upspin.Service.
 func (s *server) Close() {
-	const op = "dir/server.Close"
+	const op errors.Op = "dir/server.Close"
 
 	// Remove this user's tree from the cache. This allows it to be
 	// garbage-collected even if other servers have pointers into the
@@ -903,7 +903,7 @@
 // errPerm checks whether the user has any right to the given path, and if so
 // returns a Permission error. Otherwise it returns a Private error.
 // This is used to prevent probing of the name space.
-func (s *server) errPerm(op string, p path.Parsed, opts ...options) error {
+func (s *server) errPerm(op errors.Op, p path.Parsed, opts ...options) error {
 	// Before returning, check that the user has the right to know,
 	// to prevent leaking the name space.
 	if hasAny, _, err := s.hasRight(access.AnyRight, p, opts...); err != nil {
@@ -920,7 +920,7 @@
 // returns the entry and ErrFollowLink. If the use has no rights, it returns a
 // NotExist error. This is used to prevent probing of the name space using
 // links.
-func (s *server) errLink(op string, link *upspin.DirEntry, opts ...options) (*upspin.DirEntry, error) {
+func (s *server) errLink(op errors.Op, link *upspin.DirEntry, opts ...options) (*upspin.DirEntry, error) {
 	p, err := path.Parse(link.Name)
 	if err != nil {
 		return nil, errors.E(op, errors.Internal, link.Name, err)
@@ -953,7 +953,7 @@
 }
 
 // newOptMetric creates a new options populated with a metric for operation op.
-func newOptMetric(op string) (options, *metric.Metric) {
+func newOptMetric(op errors.Op) (options, *metric.Metric) {
 	m, sp := metric.NewSpan(op)
 	opts := options{
 		span: sp,
@@ -975,7 +975,7 @@
 
 // subspan creates a span for an operation op in the given option. It returns
 // a new option with the new span, for passing along subfunctions.
-func subspan(op string, opts []options) (options, *metric.Span) {
+func subspan(op errors.Op, opts []options) (options, *metric.Span) {
 	s := span(opts).StartSpan(op)
 	return options{span: s}, s
 }
diff --git a/vendor/upspin.io/dir/server/serverlog/log.go b/vendor/upspin.io/dir/server/serverlog/log.go
index 283a573..bd1612c 100644
--- a/vendor/upspin.io/dir/server/serverlog/log.go
+++ b/vendor/upspin.io/dir/server/serverlog/log.go
@@ -981,7 +981,7 @@
 		return nil, errors.E(errors.IO, err)
 	}
 	if len(buf) == 0 {
-		return nil, errors.E(errors.NotExist, errors.Str("no root for user"))
+		return nil, errors.E(errors.NotExist, "no root for user")
 	}
 	var root upspin.DirEntry
 	more, err := root.Unmarshal(buf)
@@ -1112,11 +1112,11 @@
 		return 0, errors.E(errors.IO, err)
 	}
 	if len(buf) == 0 {
-		return 0, errors.E(errors.NotExist, cp.user.Name(), errors.Str("no log offset for user"))
+		return 0, errors.E(errors.NotExist, cp.user.Name(), "no log offset for user")
 	}
 	offset, n := binary.Varint(buf)
 	if n <= 0 {
-		return 0, errors.E(errors.IO, errors.Str("invalid offset read"))
+		return 0, errors.E(errors.IO, "invalid offset read")
 	}
 	return offset, nil
 }
@@ -1129,7 +1129,7 @@
 // saveOffset saves to stable storage the offset to process next.
 func (cp *checkpoint) saveOffset(offset int64) error {
 	if offset < 0 {
-		return errors.E(errors.Invalid, errors.Str("negative offset"))
+		return errors.E(errors.Invalid, "negative offset")
 	}
 	var tmp [16]byte // For use by PutVarint.
 	n := binary.PutVarint(tmp[:], offset)
diff --git a/vendor/upspin.io/dir/server/snapshot.go b/vendor/upspin.io/dir/server/snapshot.go
index 211aead..92a643c 100644
--- a/vendor/upspin.io/dir/server/snapshot.go
+++ b/vendor/upspin.io/dir/server/snapshot.go
@@ -97,7 +97,7 @@
 // snapshotAll scans all roots that have a +snapshot suffix, determines whether
 // it's time to perform a new snapshot for them and if so snapshots them.
 func (s *server) snapshotAll() error {
-	const op = "dir/server.snapshotAll"
+	const op errors.Op = "dir/server.snapshotAll"
 	users, err := serverlog.ListUsersWithSuffix(snapshotSuffix, s.logDir)
 	if err != nil {
 		log.Error.Printf("%s: error listing snapshot users: %s", op, err)
@@ -148,7 +148,7 @@
 // shouldSnapshot reports whether it's time to snapshot the given configuration.
 // It also returns the parsed path of where the snapshot will be made.
 func (s *server) shouldSnapshot(cfg *snapshotConfig) (bool, path.Parsed, error) {
-	const op = "dir/server.shouldSnapshot"
+	const op errors.Op = "dir/server.shouldSnapshot"
 
 	p, err := s.snapshotDir(cfg)
 	if err != nil {
@@ -163,7 +163,7 @@
 	entries, _, err := tree.List(p)
 	if err == upspin.ErrFollowLink {
 		// We need to get the real entry and we cannot resolve links on our own.
-		return false, path.Parsed{}, errors.E(op, errors.Internal, p.Path(), errors.Str("cannot follow a link to snapshot"))
+		return false, path.Parsed{}, errors.E(op, errors.Internal, p.Path(), "cannot follow a link to snapshot")
 	} else if err != nil && !errors.Is(errors.NotExist, err) {
 		// Some other error. Abort.
 		return false, path.Parsed{}, errors.E(op, err)
@@ -274,7 +274,7 @@
 	}
 	_, _, err = tree.Lookup(name)
 	if err == upspin.ErrFollowLink {
-		return errors.E(errors.Internal, errors.Str("cannot mkdir through a link"))
+		return errors.E(errors.Internal, "cannot mkdir through a link")
 	}
 	if err != nil && !errors.Is(errors.NotExist, err) {
 		// Real error. Abort.
@@ -331,7 +331,7 @@
 // control entry we expect in order to start a new snapshot.
 func isValidSnapshotControlEntry(entry *upspin.DirEntry) error {
 	if len(entry.Blocks) != 0 || entry.IsLink() || entry.IsDir() {
-		return errors.E(errors.Invalid, entry.Name, errors.Str("snapshot control entry must be an empty file"))
+		return errors.E(errors.Invalid, entry.Name, "snapshot control entry must be an empty file")
 	}
 	return nil
 }
diff --git a/vendor/upspin.io/dir/server/tree/blocks.go b/vendor/upspin.io/dir/server/tree/blocks.go
index 50a4c11..5156693 100644
--- a/vendor/upspin.io/dir/server/tree/blocks.go
+++ b/vendor/upspin.io/dir/server/tree/blocks.go
@@ -28,7 +28,7 @@
 
 	// Can't pack a non-dir entry. Something went bad if we got here.
 	if !entry.IsDir() {
-		err := errors.E(errors.Internal, errors.Str("can't pack non-dir entry"))
+		err := errors.E(errors.Internal, "can't pack non-dir entry")
 		return err
 	}
 
@@ -50,14 +50,14 @@
 	for _, kid := range kids {
 		if kid.dirty {
 			// We should write nodes from the bottom up, so this should never happen.
-			return errors.E(kid.entry.Name, errors.Internal, errors.Str("kid node is dirty"))
+			return errors.E(kid.entry.Name, errors.Internal, "kid node is dirty")
 		}
 		// Check whether there are any empty Blocks or locations that
 		// are non-empty dirs or files.
 		if len(kid.kids) != 0 {
 			for _, b := range kid.entry.Blocks {
 				if len(b.Location.Reference) == 0 || b.Size == 0 {
-					return errors.E(kid.entry.Name, errors.Internal, errors.Str("empty directory block when there exist kid blocks"))
+					return errors.E(kid.entry.Name, errors.Internal, "empty directory block when there exist kid blocks")
 				}
 			}
 		}
@@ -171,8 +171,7 @@
 		}
 		if _, exists := kids[elem]; exists {
 			// Trying to re-add an existing child. Something is amiss.
-			return nil, errors.E(errors.Internal, kid.Name,
-				errors.Str("re-adding an existing element in the Tree"))
+			return nil, errors.E(errors.Internal, kid.Name, "re-adding an existing element in the Tree")
 		}
 		kids[elem] = &node{entry: kid}
 	}
diff --git a/vendor/upspin.io/dir/server/tree/tree.go b/vendor/upspin.io/dir/server/tree/tree.go
index 8ae4ae2..5b1f02f 100644
--- a/vendor/upspin.io/dir/server/tree/tree.go
+++ b/vendor/upspin.io/dir/server/tree/tree.go
@@ -92,25 +92,25 @@
 // returning an inconsistent new tree if log is unprocessed.
 func New(config upspin.Config, user *serverlog.User) (*Tree, error) {
 	if config == nil {
-		return nil, errors.E(errors.Invalid, errors.Str("config is nil"))
+		return nil, errors.E(errors.Invalid, "config is nil")
 	}
 	if user == nil {
-		return nil, errors.E(errors.Invalid, errors.Str("user is nil"))
+		return nil, errors.E(errors.Invalid, "user is nil")
 	}
 	if config.StoreEndpoint().Transport == upspin.Unassigned {
-		return nil, errors.E(errors.Invalid, errors.Str("unassigned store endpoint"))
+		return nil, errors.E(errors.Invalid, "unassigned store endpoint")
 	}
 	if config.KeyEndpoint().Transport == upspin.Unassigned {
-		return nil, errors.E(errors.Invalid, errors.Str("unassigned key endpoint"))
+		return nil, errors.E(errors.Invalid, "unassigned key endpoint")
 	}
 	if config.Factotum() == nil {
-		return nil, errors.E(errors.Invalid, errors.Str("factotum is nil"))
+		return nil, errors.E(errors.Invalid, "factotum is nil")
 	}
 	if config.UserName() == "" {
-		return nil, errors.E(errors.Invalid, errors.Str("username in tree config is empty"))
+		return nil, errors.E(errors.Invalid, "username in tree config is empty")
 	}
 	if user.Name() == "" {
-		return nil, errors.E(errors.Invalid, errors.Str("username in log is empty"))
+		return nil, errors.E(errors.Invalid, "username in log is empty")
 	}
 	packer := pack.Lookup(config.Packing())
 	if packer == nil {
@@ -227,7 +227,7 @@
 
 	if dstDir.IsRoot() {
 		// TODO: handle this later. It might come in handy for reinstating an old root.
-		return nil, errors.E(errors.Invalid, errors.Str("can't PutDir at the root"))
+		return nil, errors.E(errors.Invalid, "can't PutDir at the root")
 	}
 
 	// The destination must not exist nor cross a link.
@@ -254,7 +254,7 @@
 	// Put the synthetic node into the tree at dst.
 	n, err := t.put(dstDir, &existingEntryNode.entry)
 	if err == upspin.ErrFollowLink {
-		return nil, errors.E(errors.Invalid, dstDir.Path(), errors.Str("path cannot contain a link"))
+		return nil, errors.E(errors.Invalid, dstDir.Path(), "path cannot contain a link")
 	}
 	if err != nil {
 		return nil, err
@@ -298,7 +298,7 @@
 	}
 	nElem := parentPath.NElem()
 	if nodePath.Drop(1).Path() != parentPath.Path() {
-		err := errors.E(nodePath.Path(), errors.Internal, errors.Str("parent path does match parent of dir path"))
+		err := errors.E(nodePath.Path(), errors.Internal, "parent path does match parent of dir path")
 		log.Error.Print(err)
 		return err
 	}
@@ -338,7 +338,7 @@
 		// only their parents (directories), which have their kids'
 		// names and references packed in them.
 		if !n.entry.IsDir() {
-			err := errors.E(errors.Internal, n.entry.Name, errors.Str("marking non-dir dirty"))
+			err := errors.E(errors.Internal, n.entry.Name, "marking non-dir dirty")
 			log.Error.Printf("%s", err)
 			return err
 		}
@@ -429,12 +429,10 @@
 // t.mu must be held.
 func (t *Tree) loadKids(parent *node) error {
 	if parent.dirty {
-		return errors.E(errors.Internal, parent.entry.Name,
-			errors.Str("trying to load a block from storage when the node is dirty"))
+		return errors.E(errors.Internal, parent.entry.Name, "trying to load a block from storage when the node is dirty")
 	}
 	if len(parent.kids) > 0 {
-		return errors.E(errors.Internal, parent.entry.Name,
-			errors.Str("attempt to reload kids for populated node"))
+		return errors.E(errors.Internal, parent.entry.Name, "attempt to reload kids for populated node")
 	}
 	kids, err := t.load(&parent.entry)
 	if err != nil {
@@ -470,11 +468,11 @@
 	// Do we have a root already?
 	if t.root != nil {
 		// Root already exists.
-		return errors.E(errors.Exist, errors.Str("root already created"))
+		return errors.E(errors.Exist, "root already created")
 	}
 	// Check that we're trying to create a root for the owner of the Tree only.
 	if p.User() != t.user.Name() {
-		return errors.E(p.User(), p.Path(), errors.Invalid, errors.Str("can't create root for another user"))
+		return errors.E(p.User(), p.Path(), errors.Invalid, "can't create root for another user")
 	}
 	_, err := t.user.Root()
 	if err != nil && !errors.Is(errors.NotExist, err) {
@@ -483,7 +481,7 @@
 	}
 	// To be sure, the log must be empty too (or t.root wouldn't be empty).
 	if t.user.AppendOffset() != 0 {
-		err := errors.E(errors.Internal, errors.Str("index not empty, but root not found"))
+		err := errors.E(errors.Internal, "index not empty, but root not found")
 		log.Error.Print(err)
 		return err
 	}
@@ -633,7 +631,7 @@
 // t.mu must be held.
 func (t *Tree) deleteRoot() error {
 	if t.root == nil {
-		return errors.E(errors.NotExist, errors.Str("root does not exist"))
+		return errors.E(errors.NotExist, "root does not exist")
 	}
 	log.Debug.Printf("Deleting root %q", t.root.entry.Name)
 	if len(t.root.kids) > 0 {
diff --git a/vendor/upspin.io/dir/server/tree/watch.go b/vendor/upspin.io/dir/server/tree/watch.go
index 5574aed..b65b4cf 100644
--- a/vendor/upspin.io/dir/server/tree/watch.go
+++ b/vendor/upspin.io/dir/server/tree/watch.go
@@ -34,8 +34,8 @@
 )
 
 var (
-	errTimeout = errors.E(errors.IO, errors.Str("channel operation timed out"))
-	errClosed  = errors.E(errors.IO, errors.Str("channel closed"))
+	errTimeout = errors.E(errors.IO, "channel operation timed out")
+	errClosed  = errors.E(errors.IO, "channel closed")
 )
 
 // watcher holds together the done channel and the event channel for a given
diff --git a/vendor/upspin.io/dir/unassigned/unassigned.go b/vendor/upspin.io/dir/unassigned/unassigned.go
index dc949ff..36c76fa 100644
--- a/vendor/upspin.io/dir/unassigned/unassigned.go
+++ b/vendor/upspin.io/dir/unassigned/unassigned.go
@@ -22,31 +22,31 @@
 
 // Glob implements upspin.DirServer.Glob.
 func (Server) Glob(pattern string) ([]*upspin.DirEntry, error) {
-	const op = "dir/Server.Glob"
+	const op errors.Op = "dir/Server.Glob"
 	return nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
 // Put implements upspin.DirServer.Put.
 func (Server) Put(entry *upspin.DirEntry) (*upspin.DirEntry, error) {
-	const op = "dir/Server.Put"
+	const op errors.Op = "dir/Server.Put"
 	return nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
 // WhichAccess implements upspin.DirServer.WhichAccess.
 func (Server) WhichAccess(pathName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/Server.WhichAccess"
+	const op errors.Op = "dir/Server.WhichAccess"
 	return nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
 // Delete implements upspin.DirServer.Delete.
 func (Server) Delete(pathName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/Server.Delete"
+	const op errors.Op = "dir/Server.Delete"
 	return nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
 // Lookup implements upspin.DirServer.Lookup.
 func (Server) Lookup(pathName upspin.PathName) (*upspin.DirEntry, error) {
-	const op = "dir/Server.Lookup"
+	const op errors.Op = "dir/Server.Lookup"
 	return nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
@@ -66,9 +66,9 @@
 
 // Dial implements upspin.Service.
 func (Server) Dial(config upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "dir/Server.Dial"
+	const op errors.Op = "dir/Server.Dial"
 	if e.Transport != upspin.Unassigned {
-		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, errors.E(op, errors.Invalid, "unrecognized transport")
 	}
 
 	return Server{e}, nil
diff --git a/vendor/upspin.io/errors/errors.go b/vendor/upspin.io/errors/errors.go
index 34edda5..5e2e34d 100644
--- a/vendor/upspin.io/errors/errors.go
+++ b/vendor/upspin.io/errors/errors.go
@@ -27,7 +27,7 @@
 	User upspin.UserName
 	// Op is the operation being performed, usually the name of the method
 	// being invoked (Get, Put, etc.). It should not contain an at sign @.
-	Op string
+	Op Op
 	// Kind is the class of error, such as permission failure,
 	// or "Other" if its class is unknown or irrelevant.
 	Kind Kind
@@ -48,6 +48,10 @@
 	_ encoding.BinaryMarshaler   = (*Error)(nil)
 )
 
+// Op describes an operation, usually as the package and method,
+// such as "key/server.Lookup".
+type Op string
+
 // Separator is the string used to separate nested errors. By
 // default, to make errors easier on the eye, nested errors are
 // indented on a new line. A server may instead choose to keep each
@@ -127,9 +131,15 @@
 //		The Upspin path name of the item being accessed.
 //	upspin.UserName
 //		The Upspin name of the user attempting the operation.
-//	string
+//	errors.Op
 //		The operation being performed, usually the method
-//		being invoked (Get, Put, etc.)
+//		being invoked (Get, Put, etc.).
+//	string
+//		Treated as an error message and assigned to the
+//		Err field after a call to errors.Str. To avoid a common
+//		class of misuse, if the string contains an @, it will be
+//		treated as a PathName or UserName, as appropriate. Use
+//		errors.Str explicitly to avoid this special-casing.
 //	errors.Kind
 //		The class of error, such as permission failure.
 //	error
@@ -152,6 +162,8 @@
 			e.Path = arg
 		case upspin.UserName:
 			e.User = arg
+		case Op:
+			e.Op = arg
 		case string:
 			// Someone might accidentally call us with a user or path name
 			// that is not of the right type. Take care of that and log it.
@@ -169,7 +181,7 @@
 				}
 				continue
 			}
-			e.Op = arg
+			e.Err = Str(arg)
 		case Kind:
 			e.Kind = arg
 		case *Error:
@@ -239,7 +251,7 @@
 	}
 	if e.Op != "" {
 		pad(b, ": ")
-		b.WriteString(e.Op)
+		b.WriteString(string(e.Op))
 	}
 	if e.Kind != 0 {
 		pad(b, ": ")
@@ -296,7 +308,7 @@
 	}
 	b = appendString(b, string(e.Path))
 	b = appendString(b, string(e.User))
-	b = appendString(b, e.Op)
+	b = appendString(b, string(e.Op))
 	var tmp [16]byte // For use by PutVarint.
 	N := binary.PutVarint(tmp[:], int64(e.Kind))
 	b = append(b, tmp[:N]...)
@@ -356,7 +368,7 @@
 	}
 	data, b = getBytes(b)
 	if data != nil {
-		e.Op = string(data)
+		e.Op = Op(data)
 	}
 	k, N := binary.Varint(b)
 	e.Kind = Kind(k)
diff --git a/vendor/upspin.io/factotum/factotum.go b/vendor/upspin.io/factotum/factotum.go
index 4df20a2..1ae1184 100644
--- a/vendor/upspin.io/factotum/factotum.go
+++ b/vendor/upspin.io/factotum/factotum.go
@@ -57,7 +57,7 @@
 // best local means of protecting private keys. Please do not break the abstraction
 // by hand coding direct generation or use of private keys.
 func NewFromDir(dir string) (upspin.Factotum, error) {
-	const op = "factotum.NewFromDir"
+	const op errors.Op = "factotum.NewFromDir"
 
 	privBytes, err := readFile(op, dir, "secret.upspinkey")
 	if err != nil {
@@ -77,19 +77,19 @@
 	}
 	s2 = stripCR(s2)
 
-	return newFactotum(fmt.Sprintf("%s(%q)", op, dir), pubBytes, privBytes, s2)
+	return newFactotum(errors.Op(fmt.Sprintf("%s(%q)", op, dir)), pubBytes, privBytes, s2)
 }
 
 // NewFromKeys returns a new Factotum by providing it with the raw
 // representation of an Upspin user's public, private and optionally, archived
 // keys.
 func NewFromKeys(public, private, archived []byte) (upspin.Factotum, error) {
-	const op = "factotum.NewFromKeys"
+	const op errors.Op = "factotum.NewFromKeys"
 	return newFactotum(op, public, private, archived)
 }
 
 // newFactotum creates a new Factotum using the given keys.
-func newFactotum(op string, public, private, archived []byte) (upspin.Factotum, error) {
+func newFactotum(op errors.Op, public, private, archived []byte) (upspin.Factotum, error) {
 	pfk, err := makeKey(upspin.PublicKey(public), string(private))
 	if err != nil {
 		return nil, errors.E(op, err)
@@ -237,7 +237,7 @@
 
 // ScalarMult is the bare private key operator, used in unwrapping packed data.
 func (f factotum) ScalarMult(keyHash []byte, curve elliptic.Curve, x, y *big.Int) (sx, sy *big.Int, err error) {
-	const op = "factotum.ScalarMult"
+	const op errors.Op = "factotum.ScalarMult"
 	var h keyHashArray
 	copy(h[:], keyHash)
 	fk, ok := f.keys[h]
@@ -258,7 +258,7 @@
 	fk := f.keys[f.current]
 	curveLength := (fk.ecdsaKeyPair.Curve.Params().N.BitLen() + 7) / 8
 	if len(hash) > curveLength {
-		return sig0, errors.E(errors.Invalid, errors.Str("hash is too long to Sign"))
+		return sig0, errors.E(errors.Invalid, "hash is too long to Sign")
 	}
 	r, s, err := ecdsa.Sign(rand.Reader, &fk.ecdsaKeyPair, hash)
 	if err != nil {
@@ -275,7 +275,7 @@
 		return err
 	}
 	if !ecdsa.Verify(ecdsaPubKey, hash, sig.R, sig.S) {
-		return errors.E(errors.Invalid, errors.Str("signature does not match"))
+		return errors.E(errors.Invalid, "signature does not match")
 	}
 	return nil
 }
@@ -294,15 +294,15 @@
 
 // PublicKeyFromHash returns the user's public key with matching keyHash.
 func (f factotum) PublicKeyFromHash(keyHash []byte) (upspin.PublicKey, error) {
-	const op = "factotum.PublicKeyFromHash"
+	const op errors.Op = "factotum.PublicKeyFromHash"
 	if len(keyHash) == 0 {
-		return "", errors.E(op, errors.Invalid, errors.Errorf("invalid keyHash"))
+		return "", errors.E(op, errors.Invalid, "invalid keyHash")
 	}
 	var h keyHashArray
 	copy(h[:], keyHash)
 	fk, ok := f.keys[h]
 	if !ok {
-		return "", errors.E(op, errors.NotExist, errors.Errorf("no such key"))
+		return "", errors.E(op, errors.NotExist, "no such key")
 	}
 	return fk.public, nil
 }
@@ -318,7 +318,7 @@
 // parsePrivateKey returns an ECDSA private key given a user's ECDSA public key and a
 // string representation of the private key.
 func parsePrivateKey(publicKey *ecdsa.PublicKey, privateKey string) (priv *ecdsa.PrivateKey, err error) {
-	const op = "factotum.PublicKeyFromHash"
+	const op errors.Op = "factotum.PublicKeyFromHash"
 	var d big.Int
 	err = d.UnmarshalText([]byte(clean(privateKey)))
 	if err != nil {
@@ -326,7 +326,7 @@
 	}
 	x, y := publicKey.Curve.ScalarBaseMult(d.Bytes())
 	if x.Cmp(publicKey.X) != 0 || y.Cmp(publicKey.Y) != 0 {
-		return nil, errors.E(op, errors.Invalid, errors.Errorf("public and private keys do not correspond"))
+		return nil, errors.E(op, errors.Invalid, "public and private keys do not correspond")
 	}
 	return &ecdsa.PrivateKey{PublicKey: *publicKey, D: &d}, nil
 }
@@ -334,7 +334,7 @@
 // ParsePublicKey takes an Upspin representation of a public key and converts it into an ECDSA public key.
 // The Upspin string representation uses \n as newline no matter what native OS it runs on.
 func ParsePublicKey(public upspin.PublicKey) (*ecdsa.PublicKey, error) {
-	const op = "factotum.ParsePublicKey"
+	const op errors.Op = "factotum.ParsePublicKey"
 	fields := strings.Split(string(public), "\n")
 	if len(fields) != 4 { // 4 is because string should be terminated by \n, hence fields[3]==""
 		return nil, errors.E(op, errors.Invalid, errors.Errorf("expected keytype, two big ints and a newline; got %d %v", len(fields), fields))
@@ -364,7 +364,7 @@
 	return &ecdsa.PublicKey{Curve: curve, X: &x, Y: &y}, nil
 }
 
-func readFile(op, dir, name string) ([]byte, error) {
+func readFile(op errors.Op, dir, name string) ([]byte, error) {
 	b, err := ioutil.ReadFile(filepath.Join(dir, name))
 	if os.IsNotExist(err) {
 		return nil, errors.E(op, errors.NotExist, err)
diff --git a/vendor/upspin.io/flags/flags.go b/vendor/upspin.io/flags/flags.go
index 184058a..629bdb6 100644
--- a/vendor/upspin.io/flags/flags.go
+++ b/vendor/upspin.io/flags/flags.go
@@ -136,7 +136,8 @@
 	"addr": strVar(&NetAddr, "addr", NetAddr, "publicly accessible network address (`host:port`)"),
 	"blocksize": &flagVar{
 		set: func(fs *flag.FlagSet) {
-			fs.Var(&blockSize, "blocksize", "`size` of blocks when writing large files")
+			usage := fmt.Sprintf("`size` of blocks when writing large files (default %d)", defaultBlockSize)
+			fs.Var(&blockSize, "blocksize", usage)
 		},
 		arg: func() string {
 			if BlockSize == defaultBlockSize {
diff --git a/vendor/upspin.io/key/inprocess/key.go b/vendor/upspin.io/key/inprocess/key.go
index a25a34a..f9aa5b4 100644
--- a/vendor/upspin.io/key/inprocess/key.go
+++ b/vendor/upspin.io/key/inprocess/key.go
@@ -41,7 +41,7 @@
 // with the earlier entries being the best choice; later entries are
 // fallbacks and the user's public keys, if known.
 func (s *server) Lookup(name upspin.UserName) (*upspin.User, error) {
-	const op = "key/inprocess.Lookup"
+	const op errors.Op = "key/inprocess.Lookup"
 	if err := valid.UserName(name); err != nil {
 		return nil, errors.E(op, err)
 	}
@@ -69,7 +69,7 @@
 
 // Put implements upspin.KeyServer.
 func (s *server) Put(u *upspin.User) error {
-	const op = "key/inprocess.Put"
+	const op errors.Op = "key/inprocess.Put"
 	if err := valid.User(u); err != nil {
 		return errors.E(op, err)
 	}
@@ -78,7 +78,7 @@
 		return errors.E(op, err)
 	}
 	if name == "*" {
-		return errors.E(op, errors.Invalid, u.Name, errors.Str("user has wildcard '*' in name"))
+		return errors.E(op, errors.Invalid, u.Name, "user has wildcard '*' in name")
 	}
 
 	s.db.mu.Lock()
@@ -98,9 +98,9 @@
 // Dial always returns the same instance of the service. The Transport must be InProcess
 // but the NetAddr is ignored.
 func (s *server) Dial(config upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "key/inprocess.Dial"
+	const op errors.Op = "key/inprocess.Dial"
 	if e.Transport != upspin.InProcess {
-		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, errors.E(op, errors.Invalid, "unrecognized transport")
 	}
 	return s, nil
 }
diff --git a/vendor/upspin.io/key/remote/remote.go b/vendor/upspin.io/key/remote/remote.go
index 24e6d15..f366953 100644
--- a/vendor/upspin.io/key/remote/remote.go
+++ b/vendor/upspin.io/key/remote/remote.go
@@ -84,7 +84,7 @@
 	op := r.opf("Dial", "%q, %q", config.UserName(), e)
 
 	if e.Transport != upspin.Remote {
-		return nil, op.error(errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, op.error(errors.Invalid, "unrecognized transport")
 	}
 
 	authClient, err := rpc.NewClient(config, e.NetAddr, rpc.Secure, upspin.Endpoint{})
@@ -111,13 +111,13 @@
 func (r *remote) opf(method string, format string, args ...interface{}) *operation {
 	ep := r.cfg.endpoint.String()
 	s := fmt.Sprintf("key/remote: %q: key.%s", ep, method)
-	op := &operation{s, fmt.Sprintf(format, args...)}
+	op := &operation{errors.Op(s), fmt.Sprintf(format, args...)}
 	log.Debug.Print(op)
 	return op
 }
 
 type operation struct {
-	op   string
+	op   errors.Op
 	args string
 }
 
diff --git a/vendor/upspin.io/key/server/log.go b/vendor/upspin.io/key/server/log.go
index e0e389a..f36ccea 100644
--- a/vendor/upspin.io/key/server/log.go
+++ b/vendor/upspin.io/key/server/log.go
@@ -42,8 +42,9 @@
 // PutAttempt records a KeyServer.Put attempt
 // by the given actor for the given user record.
 func (l *loggerImpl) PutAttempt(actor upspin.UserName, u *upspin.User) error {
+	const op errors.Op = errors.Op("key/gcp.Logger.PutAttempt")
 	if err := l.put(time.Now(), "put attempt", actor, u); err != nil {
-		return errors.E("key/gcp.Logger.PutAttempt", err)
+		return errors.E(op, err)
 	}
 	return nil
 }
@@ -51,8 +52,9 @@
 // PutSuccess records a successful KeyServer.Put
 // by the given actor for the given user record.
 func (l *loggerImpl) PutSuccess(actor upspin.UserName, u *upspin.User) error {
+	const op errors.Op = errors.Op("key/gcp.Logger.PutSuccess")
 	if err := l.put(time.Now(), "put success", actor, u); err != nil {
-		return errors.E("key/gcp.Logger.PutSuccess", err)
+		return errors.E(op, err)
 	}
 	return nil
 }
@@ -99,7 +101,7 @@
 
 // ReadAll returns the log bytes.
 func (l *loggerImpl) ReadAll() ([]byte, error) {
-	const op = "key/gcp.Logger.ReadAll"
+	const op errors.Op = "key/gcp.Logger.ReadAll"
 	l.mu.Lock()
 	defer l.mu.Unlock()
 
diff --git a/vendor/upspin.io/key/server/server.go b/vendor/upspin.io/key/server/server.go
index 0d6cc86..d80eea6 100644
--- a/vendor/upspin.io/key/server/server.go
+++ b/vendor/upspin.io/key/server/server.go
@@ -30,7 +30,7 @@
 // New initializes an instance of the KeyServer
 // that stores its data in the given Storage implementation.
 func New(options ...string) (upspin.KeyServer, error) {
-	const op = "key/server.New"
+	const op errors.Op = "key/server.New"
 
 	var backend string
 	var dialOpts []storage.DialOpts
@@ -44,7 +44,7 @@
 		dialOpts = append(dialOpts, storage.WithOptions(option))
 	}
 	if backend == "" {
-		return nil, errors.E(op, errors.Invalid, errors.Str(`storage "backend" option is missing`))
+		return nil, errors.E(op, errors.Invalid, `storage "backend" option is missing`)
 	}
 	s, err := storage.Dial(backend, dialOpts...)
 	if err != nil {
@@ -99,7 +99,7 @@
 
 // Lookup implements upspin.KeyServer.
 func (s *server) Lookup(name upspin.UserName) (*upspin.User, error) {
-	const op = "key/server.Lookup"
+	const op errors.Op = "key/server.Lookup"
 	m, span := metric.NewSpan(op)
 	defer m.Done()
 
@@ -114,7 +114,7 @@
 }
 
 // lookup looks up the internal user record, using caches when available.
-func (s *server) lookup(op string, name upspin.UserName, span *metric.Span) (*userEntry, error) {
+func (s *server) lookup(op errors.Op, name upspin.UserName, span *metric.Span) (*userEntry, error) {
 	// Check positive cache first.
 	if entry, found := s.cache.Get(name); found {
 		return entry.(*userEntry), nil
@@ -144,12 +144,12 @@
 
 // Put implements upspin.KeyServer.
 func (s *server) Put(u *upspin.User) error {
-	const op = "key/server.Put"
+	const op errors.Op = "key/server.Put"
 	m, span := metric.NewSpan(op)
 	defer m.Done()
 
 	if s.user == "" {
-		return errors.E(op, errors.Internal, errors.Str("not bound to user"))
+		return errors.E(op, errors.Internal, "not bound to user")
 	}
 	if err := valid.User(u); err != nil {
 		return errors.E(op, err)
@@ -211,7 +211,7 @@
 
 // canPut reports whether the current logged-in user can Put the (new or
 // existing) target user.
-func (s *server) canPut(op string, target upspin.UserName, isTargetNew bool, span *metric.Span) error {
+func (s *server) canPut(op errors.Op, target upspin.UserName, isTargetNew bool, span *metric.Span) error {
 	sp := span.StartSpan("canPut")
 	defer sp.End()
 
@@ -221,7 +221,7 @@
 	}
 	// Do not allow * wildcard in name.
 	if name == "*" {
-		return errors.E(op, errors.Invalid, target, errors.Str("user has wildcard '*' in name"))
+		return errors.E(op, errors.Invalid, target, "user has wildcard '*' in name")
 	}
 	// If the current user is the same as target, it can proceed.
 	if s.user == target {
@@ -261,7 +261,7 @@
 }
 
 // fetchUserEntry reads the user entry for a given user from the storage.
-func (s *server) fetchUserEntry(op string, name upspin.UserName) (*userEntry, error) {
+func (s *server) fetchUserEntry(op errors.Op, name upspin.UserName) (*userEntry, error) {
 	b, err := s.storage.Download(string(name))
 	if err != nil {
 		return nil, errors.E(op, name, err)
@@ -274,9 +274,9 @@
 }
 
 // putUserEntry writes the user entry for a user to the storage.
-func (s *server) putUserEntry(op string, entry *userEntry) error {
+func (s *server) putUserEntry(op errors.Op, entry *userEntry) error {
 	if entry == nil {
-		return errors.E(op, errors.Invalid, errors.Str("nil userEntry"))
+		return errors.E(op, errors.Invalid, "nil userEntry")
 	}
 	b, err := json.Marshal(entry)
 	if err != nil {
@@ -315,11 +315,11 @@
 		var sig upspin.Signature
 		var rs, ss big.Int
 		if _, ok := rs.SetString(sigFields[0], 16); !ok {
-			lastErr = errors.E(errors.Invalid, errors.Str("invalid signature field0"))
+			lastErr = errors.E(errors.Invalid, "invalid signature field0")
 			continue
 		}
 		if _, ok := ss.SetString(sigFields[1], 16); !ok {
-			lastErr = errors.E(errors.Invalid, errors.Str("invalid signature field1"))
+			lastErr = errors.E(errors.Invalid, "invalid signature field1")
 			continue
 		}
 		sig.R = &rs
@@ -339,7 +339,7 @@
 
 // Log implements Logger.
 func (s *server) Log() ([]byte, error) {
-	const op = "key/server.Log"
+	const op errors.Op = "key/server.Log"
 
 	data, err := s.logger.ReadAll()
 	if err != nil {
diff --git a/vendor/upspin.io/key/unassigned/unassigned.go b/vendor/upspin.io/key/unassigned/unassigned.go
index ebaf5dd..44c4c09 100644
--- a/vendor/upspin.io/key/unassigned/unassigned.go
+++ b/vendor/upspin.io/key/unassigned/unassigned.go
@@ -22,13 +22,13 @@
 
 // Lookup implements upspin.KeysServer.Lookup.
 func (Server) Lookup(name upspin.UserName) (*upspin.User, error) {
-	const op = "key/Server.Lookup"
+	const op errors.Op = "key/Server.Lookup"
 	return nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
 // Put implements upspin.KeysServer.Put.
 func (Server) Put(user *upspin.User) error {
-	const op = "key/Server.Put"
+	const op errors.Op = "key/Server.Put"
 	return errors.E(op, errors.Invalid, unassignedErr)
 }
 
@@ -43,9 +43,9 @@
 
 // Dial implements upspin.Service.
 func (Server) Dial(config upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "key/Server.Dial"
+	const op errors.Op = "key/Server.Dial"
 	if e.Transport != upspin.Unassigned {
-		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, errors.E(op, errors.Invalid, "unrecognized transport")
 	}
 
 	return Server{e}, nil
diff --git a/vendor/upspin.io/key/usercache/cache.go b/vendor/upspin.io/key/usercache/cache.go
index ec57f7f..a54a2e1 100644
--- a/vendor/upspin.io/key/usercache/cache.go
+++ b/vendor/upspin.io/key/usercache/cache.go
@@ -79,7 +79,7 @@
 
 // Lookup implements upspin.KeyServer.
 func (c *userCacheServer) Lookup(name upspin.UserName) (*upspin.User, error) {
-	const op = "key/usercache.Lookup"
+	const op errors.Op = "key/usercache.Lookup"
 
 	// If we have an unexpired cache entry, use it.
 	if v, ok := c.cache.entries.Get(name); ok {
@@ -108,7 +108,7 @@
 
 // Put implements upspin.KeyServer.
 func (c *userCacheServer) Put(user *upspin.User) error {
-	const op = "key/usercache.Put"
+	const op errors.Op = "key/usercache.Put"
 	if err := c.dial(); err != nil {
 		return errors.E(op, err)
 	}
diff --git a/vendor/upspin.io/metric/metric.go b/vendor/upspin.io/metric/metric.go
index 2c27adf..6f16010 100644
--- a/vendor/upspin.io/metric/metric.go
+++ b/vendor/upspin.io/metric/metric.go
@@ -11,13 +11,14 @@
 	"sync/atomic"
 	"time"
 
+	"upspin.io/errors"
 	"upspin.io/log"
 )
 
 // Metric is a named collection of spans. A span measures time from the beginning of an event
 // (for example, an RPC request) until its completion.
 type Metric struct {
-	Name string
+	Name errors.Op
 
 	mu    sync.Mutex // protects all fields below
 	spans []*Span
@@ -33,7 +34,7 @@
 
 // A Span measures time from the beginning of an event (for example, an RPC request) until its completion.
 type Span struct {
-	Name       string
+	Name       errors.Op
 	StartTime  time.Time
 	EndTime    time.Time
 	Kind       Kind    // Server, Client or Other kind of metric span.
@@ -70,14 +71,14 @@
 
 // New creates a new named metric. If name is non-empty, it will prefix every
 // descendant's Span name.
-func New(name string) *Metric {
+func New(name errors.Op) *Metric {
 	return &Metric{
 		Name: name,
 	}
 }
 
 // NewSpan creates a new unamed metric with a newly-started named span.
-func NewSpan(name string) (*Metric, *Span) {
+func NewSpan(name errors.Op) (*Metric, *Span) {
 	m := New(name)
 	return m, m.StartSpan(name)
 }
@@ -97,7 +98,7 @@
 
 // StartSpan starts a new span of the metric with implicit start time being the current time and Kind being Server.
 // Spans need not be contiguous and may or may not overlap.
-func (m *Metric) StartSpan(name string) *Span {
+func (m *Metric) StartSpan(name errors.Op) *Span {
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	// Lazily allocate the spans slice.
@@ -151,7 +152,7 @@
 
 // StartSpan starts a new span as a child of s with start time set to the current time.
 // It may return nil if the parent Metric of s is Done.
-func (s *Span) StartSpan(name string) *Span {
+func (s *Span) StartSpan(name errors.Op) *Span {
 	if s.Parent == nil {
 		log.Error.Printf("metric: parent metric of span %q is nil", s.Name)
 		return nil
diff --git a/vendor/upspin.io/pack/ee/create.go b/vendor/upspin.io/pack/ee/create.go
index d8533cd..19eb478 100644
--- a/vendor/upspin.io/pack/ee/create.go
+++ b/vendor/upspin.io/pack/ee/create.go
@@ -50,7 +50,7 @@
 
 // CreateKeys creates a key pair based on the chosen curve and a slice of entropy.
 func CreateKeys(curveName string, entropy []byte) (public upspin.PublicKey, private string, err error) {
-	const op = "pack/ee.CreateKeys"
+	const op errors.Op = "pack/ee.CreateKeys"
 	var curve elliptic.Curve
 	switch curveName {
 	case "p256":
diff --git a/vendor/upspin.io/pack/ee/ee.go b/vendor/upspin.io/pack/ee/ee.go
index afe5271..60443ad 100644
--- a/vendor/upspin.io/pack/ee/ee.go
+++ b/vendor/upspin.io/pack/ee/ee.go
@@ -86,7 +86,7 @@
 }
 
 func (ee ee) Pack(cfg upspin.Config, d *upspin.DirEntry) (upspin.BlockPacker, error) {
-	const op = "pack/ee.Pack"
+	const op errors.Op = "pack/ee.Pack"
 	if err := pack.CheckPacking(ee, d); err != nil {
 		return nil, errors.E(op, errors.Invalid, d.Name, err)
 	}
@@ -141,7 +141,7 @@
 }
 
 func (bp *blockPacker) Pack(cleartext []byte) (ciphertext []byte, err error) {
-	const op = "pack/ee.blockPacker.Pack"
+	const op errors.Op = "pack/ee.blockPacker.Pack"
 	if err := internal.CheckLocationSet(bp.entry); err != nil {
 		return nil, err
 	}
@@ -181,7 +181,7 @@
 }
 
 func (bp *blockPacker) Close() error {
-	const op = "pack/ee.blockPacker.Close"
+	const op errors.Op = "pack/ee.blockPacker.Close"
 	// Zero out encryption key when we're done.
 	defer zeroSlice(&bp.dkey)
 
@@ -252,7 +252,7 @@
 }
 
 func (ee ee) Unpack(cfg upspin.Config, d *upspin.DirEntry) (upspin.BlockUnpacker, error) {
-	const op = "pack/ee.Unpack"
+	const op errors.Op = "pack/ee.Unpack"
 	if err := pack.CheckPacking(ee, d); err != nil {
 		return nil, errors.E(op, errors.Invalid, d.Name, err)
 	}
@@ -269,7 +269,7 @@
 
 	// Check that our stored+signed block checksum matches the sum of the actual blocks.
 	if !bytes.Equal(internal.BlockSum(d.Blocks), pd.blockSum) {
-		return nil, errors.E(op, d.Name, errors.Str("checksum mismatch"))
+		return nil, errors.E(op, d.Name, "checksum mismatch")
 	}
 
 	// Fetch writer public key.
@@ -342,12 +342,12 @@
 }
 
 func (bp *blockUnpacker) Unpack(ciphertext []byte) (cleartext []byte, err error) {
-	const op = "pack/ee.blockUnpacker.Unpack"
+	const op errors.Op = "pack/ee.blockUnpacker.Unpack"
 	// Validate checksum.
 	b := sha256.Sum256(ciphertext)
 	sum := b[:]
 	if got, want := sum, bp.entry.Blocks[bp.Block].Packdata; !bytes.Equal(got, want) {
-		return nil, errors.E(op, bp.entry.Name, errors.Str("checksum mismatch"))
+		return nil, errors.E(op, bp.entry.Name, "checksum mismatch")
 	}
 
 	cleartext = bp.buf.Bytes(len(ciphertext))
@@ -367,7 +367,7 @@
 // ReaderHashes returns SHA-256 hashes of the public keys able to decrypt the
 // associated ciphertext.
 func (ee ee) ReaderHashes(pd []byte) (readers [][]byte, err error) {
-	const op = "pack/ee.ReaderHashes"
+	const op errors.Op = "pack/ee.ReaderHashes"
 	var d packdata
 	if err := d.Unmarshal(pd); err != nil {
 		return nil, errors.E(op, errors.Invalid, err)
@@ -381,7 +381,6 @@
 
 // Share extracts the file decryption key from the packdata, wraps it for a revised list of readers, and updates packdata.
 func (ee ee) Share(cfg upspin.Config, readers []upspin.PublicKey, packdataSlice []*[]byte) {
-
 	// A Packdata holds a cipherSum, a Signature, and a list of wrapped keys.
 	// Share updates the wrapped keys, leaving the other two fields unchanged.
 	// For efficiency, Share() reuses the wrapped key for readers common to the old and new lists.
@@ -404,7 +403,6 @@
 
 	// For each packdata, wrap for new readers.
 	for j, d := range packdataSlice {
-
 		// Extract dkey and existing wrapped keys from packdata.
 		var dkey []byte
 		alreadyWrapped := make(map[keyHashArray]*wrappedKey)
@@ -477,17 +475,17 @@
 
 // Name implements upspin.Name.
 func (ee ee) Name(cfg upspin.Config, d *upspin.DirEntry, newName upspin.PathName) error {
-	const op = "pack/ee.Name"
+	const op errors.Op = "pack/ee.Name"
 	return ee.updateDirEntry(op, cfg, d, newName, d.Time)
 }
 
 // SetTime implements upspin.SetTime.
 func (ee ee) SetTime(cfg upspin.Config, d *upspin.DirEntry, t upspin.Time) error {
-	const op = "pack/ee.SetTime"
+	const op errors.Op = "pack/ee.SetTime"
 	return ee.updateDirEntry(op, cfg, d, d.Name, t)
 }
 
-func (ee ee) updateDirEntry(op string, cfg upspin.Config, d *upspin.DirEntry, newName upspin.PathName, newTime upspin.Time) error {
+func (ee ee) updateDirEntry(op errors.Op, cfg upspin.Config, d *upspin.DirEntry, newName upspin.PathName, newTime upspin.Time) error {
 	parsed, err := path.Parse(d.Name)
 	if err != nil {
 		return errors.E(op, err)
@@ -499,7 +497,7 @@
 	newName = parsedNew.Path()
 
 	if d.IsDir() && !parsed.Equal(parsedNew) {
-		return errors.E(op, d.Name, errors.IsDir, errors.Str("cannot rename directory"))
+		return errors.E(op, d.Name, errors.IsDir, "cannot rename directory")
 	}
 	if err := pack.CheckPacking(ee, d); err != nil {
 		return errors.E(op, errors.Invalid, d.Name, err)
@@ -555,7 +553,7 @@
 		// Decode my wrapped key using my private key
 		dkey, err = aesUnwrap(f, w)
 		if err != nil {
-			return errors.E(op, d.Name, errors.Str("unwrap failed"))
+			return errors.E(op, d.Name, "unwrap failed")
 		}
 	}
 
@@ -594,9 +592,9 @@
 
 // Countersign uses the key in factotum f to add a signature to a DirEntry that is already signed by oldKey.
 func (ee ee) Countersign(oldKey upspin.PublicKey, f upspin.Factotum, d *upspin.DirEntry) error {
-	const op = "pack/ee.Countersign"
+	const op errors.Op = "pack/ee.Countersign"
 	if d.IsDir() {
-		return errors.E(op, d.Name, errors.IsDir, errors.Str("cannot sign directory"))
+		return errors.E(op, d.Name, errors.IsDir, "cannot sign directory")
 	}
 
 	// Get ECDSA form of old key.
@@ -626,19 +624,19 @@
 	}
 	dkey, err := aesUnwrap(f, w)
 	if err != nil {
-		return errors.E(op, d.Name, errors.Str("unwrap failed"))
+		return errors.E(op, d.Name, "unwrap failed")
 	}
 
 	// Verify existing signature with oldKey.
 	vhash := f.DirEntryHash(d.SignedName, d.Link, d.Attr, d.Packing, d.Time, dkey, pd.blockSum)
 	if !ecdsa.Verify(oldPubKey, vhash, pd.sig.R, pd.sig.S) {
-		return errors.E(op, d.Name, errVerify, errors.Str("unable to verify existing signature"))
+		return errors.E(op, d.Name, errVerify, "unable to verify existing signature")
 	}
 
 	// Sign with newKey.
 	sig1, err := f.FileSign(vhash)
 	if err != nil {
-		return errors.E(op, d.Name, errVerify, errors.Str("unable to make new signature"))
+		return errors.E(op, d.Name, errVerify, "unable to make new signature")
 	}
 	pd.sig2 = pd.sig
 	pd.sig = sig1
@@ -646,7 +644,7 @@
 }
 
 func (ee ee) UnpackableByAll(d *upspin.DirEntry) (bool, error) {
-	const op = "pack/ee.UnpackableByAll"
+	const op errors.Op = "pack/ee.UnpackableByAll"
 
 	if d.Packing != upspin.EEPack {
 		p := pack.Lookup(d.Packing)
diff --git a/vendor/upspin.io/pack/eeintegrity/eeintegrity.go b/vendor/upspin.io/pack/eeintegrity/eeintegrity.go
index be51a6f..3da6ec9 100644
--- a/vendor/upspin.io/pack/eeintegrity/eeintegrity.go
+++ b/vendor/upspin.io/pack/eeintegrity/eeintegrity.go
@@ -71,7 +71,7 @@
 
 // Pack implements upspin.Packer.
 func (ei ei) Pack(cfg upspin.Config, d *upspin.DirEntry) (upspin.BlockPacker, error) {
-	const op = "pack/eeintegrity.Pack"
+	const op errors.Op = "pack/eeintegrity.Pack"
 	if err := pack.CheckPacking(ei, d); err != nil {
 		return nil, errors.E(op, errors.Invalid, d.Name, err)
 	}
@@ -97,7 +97,7 @@
 
 // Pack implements upspin.BlockPacker.
 func (bp *blockPacker) Pack(cleartext []byte) (ciphertext []byte, err error) {
-	const op = "pack/eeintegrity.blockPacker.Pack"
+	const op errors.Op = "pack/eeintegrity.blockPacker.Pack"
 	if err := internal.CheckLocationSet(bp.entry); err != nil {
 		return nil, err
 	}
@@ -133,7 +133,7 @@
 
 // Close implements upspin.BlockPacker.
 func (bp *blockPacker) Close() error {
-	const op = "pack/eeintegrity.blockPacker.Close"
+	const op errors.Op = "pack/eeintegrity.blockPacker.Close"
 	if err := internal.CheckLocationSet(bp.entry); err != nil {
 		return err
 	}
@@ -154,7 +154,7 @@
 
 // Unpack implements upspin.Packer.
 func (ei ei) Unpack(cfg upspin.Config, d *upspin.DirEntry) (upspin.BlockUnpacker, error) {
-	const op = "pack/eeintegrity.Unpack"
+	const op errors.Op = "pack/eeintegrity.Unpack"
 	if err := pack.CheckPacking(ei, d); err != nil {
 		return nil, errors.E(op, errors.Invalid, d.Name, err)
 	}
@@ -171,7 +171,7 @@
 
 	// Check that our stored+signed block checksum matches the sum of the actual blocks.
 	if got, want := internal.BlockSum(d.Blocks), hash; !bytes.Equal(got, want) {
-		return nil, errors.E(op, d.Name, errors.Str("checksum mismatch"))
+		return nil, errors.E(op, d.Name, "checksum mismatch")
 	}
 
 	// Fetch writer public key.
@@ -215,12 +215,12 @@
 
 // Unpack implements upspin.BlockUnpacker.
 func (bp *blockUnpacker) Unpack(ciphertext []byte) (cleartext []byte, err error) {
-	const op = "pack/eeintegrity.blockUpacker.Unpack"
+	const op errors.Op = "pack/eeintegrity.blockUpacker.Unpack"
 	// Validate checksum.
 	b := sha256.Sum256(ciphertext)
 	sum := b[:]
 	if got, want := sum, bp.entry.Blocks[bp.Block].Packdata; !bytes.Equal(got, want) {
-		return nil, errors.E(op, bp.entry.Name, errors.Str("checksum mismatch"))
+		return nil, errors.E(op, bp.entry.Name, "checksum mismatch")
 	}
 
 	cleartext = bp.buf.Bytes(len(ciphertext))
@@ -244,17 +244,17 @@
 
 // Name implements upspin.Name.
 func (ei ei) Name(cfg upspin.Config, d *upspin.DirEntry, newName upspin.PathName) error {
-	const op = "pack/plain.Name"
+	const op errors.Op = "pack/plain.Name"
 	return ei.updateDirEntry(op, cfg, d, newName, d.Time)
 }
 
 // SetTime implements upspin.SetTime.
 func (ei ei) SetTime(cfg upspin.Config, d *upspin.DirEntry, t upspin.Time) error {
-	const op = "pack/plain.SetTime"
+	const op errors.Op = "pack/plain.SetTime"
 	return ei.updateDirEntry(op, cfg, d, d.Name, t)
 }
 
-func (ei ei) updateDirEntry(op string, cfg upspin.Config, d *upspin.DirEntry, newName upspin.PathName, newTime upspin.Time) error {
+func (ei ei) updateDirEntry(op errors.Op, cfg upspin.Config, d *upspin.DirEntry, newName upspin.PathName, newTime upspin.Time) error {
 	parsed, err := path.Parse(d.Name)
 	if err != nil {
 		return errors.E(op, err)
@@ -266,7 +266,7 @@
 	newName = parsedNew.Path()
 
 	if d.IsDir() && !parsed.Equal(parsedNew) {
-		return errors.E(op, d.Name, errors.IsDir, errors.Str("cannot rename directory"))
+		return errors.E(op, d.Name, errors.IsDir, "cannot rename directory")
 	}
 	if err := pack.CheckPacking(ei, d); err != nil {
 		return errors.E(op, errors.Invalid, d.Name, err)
@@ -319,9 +319,9 @@
 
 // Countersign uses the key in factotum f to add a signature to a DirEntry that is already signed by oldKey.
 func (ei ei) Countersign(oldKey upspin.PublicKey, f upspin.Factotum, d *upspin.DirEntry) error {
-	const op = "pack/eeintegrity.Countersign"
+	const op errors.Op = "pack/eeintegrity.Countersign"
 	if d.IsDir() {
-		return errors.E(op, d.Name, errors.IsDir, errors.Str("cannot sign directory"))
+		return errors.E(op, d.Name, errors.IsDir, "cannot sign directory")
 	}
 
 	// Get ECDSA form of old key.
@@ -340,13 +340,13 @@
 	dkey := make([]byte, aesKeyLen)
 	vhash := f.DirEntryHash(d.SignedName, d.Link, d.Attr, d.Packing, d.Time, dkey, cipherSum)
 	if !ecdsa.Verify(oldPubKey, vhash, sig.R, sig.S) {
-		return errors.E(op, d.Name, errVerify, errors.Str("unable to verify existing signature"))
+		return errors.E(op, d.Name, errVerify, "unable to verify existing signature")
 	}
 
 	// Sign with newKey.
 	sig1, err := f.FileSign(vhash)
 	if err != nil {
-		return errors.E(op, d.Name, errVerify, errors.Str("unable to make new signature"))
+		return errors.E(op, d.Name, errVerify, "unable to make new signature")
 	}
 	pdMarshal(&d.Packdata, sig1, sig, cipherSum)
 	return nil
diff --git a/vendor/upspin.io/pack/internal/checkloc.go b/vendor/upspin.io/pack/internal/checkloc.go
index 03bd630..799307a 100644
--- a/vendor/upspin.io/pack/internal/checkloc.go
+++ b/vendor/upspin.io/pack/internal/checkloc.go
@@ -12,7 +12,7 @@
 // CheckLocationSet checks whether the previous block's Location field
 // was set, to prevent misuse of the BlockPacker API.
 func CheckLocationSet(d *upspin.DirEntry) error {
-	const op = "pack.CheckLocationSet"
+	const op errors.Op = "pack.CheckLocationSet"
 	if bs := d.Blocks; len(bs) > 0 {
 		if i := len(bs) - 1; bs[i].Location == (upspin.Location{}) {
 			return errors.E(op, d.Name, errors.Errorf("location not set for block %v", i))
diff --git a/vendor/upspin.io/pack/pack.go b/vendor/upspin.io/pack/pack.go
index 3713102..accc4a8 100644
--- a/vendor/upspin.io/pack/pack.go
+++ b/vendor/upspin.io/pack/pack.go
@@ -25,7 +25,7 @@
 func Register(packer upspin.Packer) error {
 	packing := packer.Packing()
 	if packing == upspin.UnassignedPack {
-		return errors.E(errors.Invalid, errors.Str("unassigned pack cannot be registered"))
+		return errors.E(errors.Invalid, "unassigned pack cannot be registered")
 	}
 	mu.Lock()
 	defer mu.Unlock()
diff --git a/vendor/upspin.io/pack/packutil/packdata.go b/vendor/upspin.io/pack/packutil/packdata.go
index e921a05..ad9dac7 100644
--- a/vendor/upspin.io/pack/packutil/packdata.go
+++ b/vendor/upspin.io/pack/packutil/packdata.go
@@ -13,8 +13,6 @@
 	"upspin.io/upspin"
 )
 
-var errNoKnownKeysForUser = errors.Str("no known keys for user")
-
 // PutBytes stores the varint-encoded length of src in dst, followed by a copy of src.
 // It returns the number of bytes written to dst.
 func PutBytes(dst, src []byte) int {
@@ -38,7 +36,6 @@
 
 // GetPublicKey returns the string representation of a user's public key.
 func GetPublicKey(cfg upspin.Config, user upspin.UserName) (upspin.PublicKey, error) {
-
 	// Are we requesting our own public key?
 	if string(user) == string(cfg.UserName()) {
 		return cfg.Factotum().PublicKey(), nil
@@ -52,7 +49,7 @@
 		return "", err
 	}
 	if len(u.PublicKey) == 0 {
-		return "", errors.E(user, errors.NotExist, errNoKnownKeysForUser)
+		return "", errors.E(user, errors.NotExist, "no known keys for user")
 	}
 	return u.PublicKey, nil
 }
diff --git a/vendor/upspin.io/pack/plain/plain.go b/vendor/upspin.io/pack/plain/plain.go
index c217b0d..e1f0e01 100644
--- a/vendor/upspin.io/pack/plain/plain.go
+++ b/vendor/upspin.io/pack/plain/plain.go
@@ -59,7 +59,7 @@
 }
 
 func (p plainPack) Pack(cfg upspin.Config, d *upspin.DirEntry) (upspin.BlockPacker, error) {
-	const op = "pack/plain.Pack"
+	const op errors.Op = "pack/plain.Pack"
 	if err := pack.CheckPacking(p, d); err != nil {
 		return nil, errors.E(op, errors.Invalid, d.Name, err)
 	}
@@ -79,7 +79,7 @@
 }
 
 func (bp *blockPacker) Pack(cleartext []byte) (ciphertext []byte, err error) {
-	const op = "pack/plain.blockPacker.Pack"
+	const op errors.Op = "pack/plain.blockPacker.Pack"
 	if err := internal.CheckLocationSet(bp.entry); err != nil {
 		return nil, errors.E(op, err)
 	}
@@ -108,7 +108,7 @@
 
 // Close implements upspin.BlockPacker.
 func (bp *blockPacker) Close() error {
-	const op = "pack/plain.blockPacker.Close"
+	const op errors.Op = "pack/plain.blockPacker.Close"
 	if err := internal.CheckLocationSet(bp.entry); err != nil {
 		return errors.E(op, err)
 	}
@@ -127,7 +127,7 @@
 
 // Unpack implements upspin.Packer.
 func (p plainPack) Unpack(cfg upspin.Config, d *upspin.DirEntry) (upspin.BlockUnpacker, error) {
-	const op = "pack/plain.Unpack"
+	const op errors.Op = "pack/plain.Unpack"
 	if err := pack.CheckPacking(p, d); err != nil {
 		return nil, errors.E(op, errors.Invalid, d.Name, err)
 	}
@@ -191,17 +191,17 @@
 
 // Name implements upspin.Name.
 func (p plainPack) Name(cfg upspin.Config, d *upspin.DirEntry, newName upspin.PathName) error {
-	const op = "pack/plain.Name"
+	const op errors.Op = "pack/plain.Name"
 	return p.updateDirEntry(op, cfg, d, newName, d.Time)
 }
 
 // SetTime implements upspin.SetTime.
 func (p plainPack) SetTime(cfg upspin.Config, d *upspin.DirEntry, t upspin.Time) error {
-	const op = "pack/plain.SetTime"
+	const op errors.Op = "pack/plain.SetTime"
 	return p.updateDirEntry(op, cfg, d, d.Name, t)
 }
 
-func (p plainPack) updateDirEntry(op string, cfg upspin.Config, dirEntry *upspin.DirEntry, newName upspin.PathName, newTime upspin.Time) error {
+func (p plainPack) updateDirEntry(op errors.Op, cfg upspin.Config, dirEntry *upspin.DirEntry, newName upspin.PathName, newTime upspin.Time) error {
 	parsed, err := path.Parse(dirEntry.Name)
 	if err != nil {
 		return errors.E(op, err)
@@ -213,7 +213,7 @@
 	newName = parsedNew.Path()
 
 	if dirEntry.IsDir() && !parsed.Equal(parsedNew) {
-		return errors.E(op, dirEntry.Name, errors.IsDir, errors.Str("cannot rename directory"))
+		return errors.E(op, dirEntry.Name, errors.IsDir, "cannot rename directory")
 	}
 	dirEntry.Name = newName
 	dirEntry.SignedName = dirEntry.Name
@@ -233,9 +233,9 @@
 
 // Countersign uses the key in factotum f to add a signature to a DirEntry that is already signed by oldKey.
 func (p plainPack) Countersign(oldKey upspin.PublicKey, f upspin.Factotum, d *upspin.DirEntry) error {
-	const op = "pack/plain.Countersign"
+	const op errors.Op = "pack/plain.Countersign"
 	if d.IsDir() {
-		return errors.E(op, d.Name, errors.IsDir, errors.Str("cannot sign directory"))
+		return errors.E(op, d.Name, errors.IsDir, "cannot sign directory")
 	}
 
 	// Get ECDSA form of old key.
@@ -255,13 +255,13 @@
 	sum := make([]byte, sha256.Size)
 	vhash := f.DirEntryHash(d.SignedName, d.Link, d.Attr, d.Packing, d.Time, dkey, sum)
 	if !ecdsa.Verify(oldPubKey, vhash, sig.R, sig.S) {
-		return errors.E(op, d.Name, errVerify, errors.Str("unable to verify existing signature"))
+		return errors.E(op, d.Name, errVerify, "unable to verify existing signature")
 	}
 
 	// Sign with newKey.
 	sig1, err := f.FileSign(vhash)
 	if err != nil {
-		return errors.E(op, d.Name, errVerify, errors.Str("unable to make new signature"))
+		return errors.E(op, d.Name, errVerify, "unable to make new signature")
 	}
 	pdMarshal(&d.Packdata, sig1, sig)
 	return nil
diff --git a/vendor/upspin.io/rpc/cache.go b/vendor/upspin.io/rpc/cache.go
index fd3ad95..6db03d8 100644
--- a/vendor/upspin.io/rpc/cache.go
+++ b/vendor/upspin.io/rpc/cache.go
@@ -13,7 +13,7 @@
 )
 
 func CacheEndpoint(cfg upspin.Config) (*upspin.Endpoint, error) {
-	const op = "rpc.CacheEndpoint"
+	const op errors.Op = "rpc.CacheEndpoint"
 
 	v := cfg.Value("cache")
 	switch v {
diff --git a/vendor/upspin.io/rpc/client.go b/vendor/upspin.io/rpc/client.go
index 790b868..4defd5d 100644
--- a/vendor/upspin.io/rpc/client.go
+++ b/vendor/upspin.io/rpc/client.go
@@ -91,7 +91,7 @@
 // it indicates that this connection is being used to proxy request to that
 // endpoint.
 func NewClient(cfg upspin.Config, netAddr upspin.NetAddr, security SecurityLevel, proxyFor upspin.Endpoint) (Client, error) {
-	const op = "rpc.NewClient"
+	const op errors.Op = "rpc.NewClient"
 
 	c := &httpClient{
 		proxyFor: proxyFor,
@@ -140,7 +140,7 @@
 	return c, nil
 }
 
-func (c *httpClient) makeAuthenticatedRequest(op, method string, req pb.Message) (*http.Response, bool, error) {
+func (c *httpClient) makeAuthenticatedRequest(op errors.Op, method string, req pb.Message) (*http.Response, bool, error) {
 	token, haveToken := c.authToken()
 	header := make(http.Header)
 	needServerAuth := false
@@ -163,7 +163,7 @@
 	return resp, needServerAuth, err
 }
 
-func (c *httpClient) makeRequest(op, method string, req pb.Message, header http.Header) (*http.Response, error) {
+func (c *httpClient) makeRequest(op errors.Op, method string, req pb.Message, header http.Header) (*http.Response, error) {
 	// Encode the payload.
 	payload, err := pb.Marshal(req)
 	if err != nil {
@@ -187,7 +187,7 @@
 
 // InvokeUnauthenticated implements Client.
 func (c *httpClient) InvokeUnauthenticated(method string, req, resp pb.Message) error {
-	const op = "rpc.InvokeUnauthenticated"
+	const op errors.Op = "rpc.InvokeUnauthenticated"
 
 	httpResp, err := c.makeRequest(op, method, req, make(http.Header))
 	if err != nil {
@@ -199,10 +199,10 @@
 
 // Invoke implements Client.
 func (c *httpClient) Invoke(method string, req, resp pb.Message, stream ResponseChan, done <-chan struct{}) error {
-	const op = "rpc.Invoke"
+	const op errors.Op = "rpc.Invoke"
 
 	if (resp == nil) == (stream == nil) {
-		return errors.E(op, errors.Str("exactly one of resp and stream must be nil"))
+		return errors.E(op, "exactly one of resp and stream must be nil")
 	}
 
 	var httpResp *http.Response
@@ -250,7 +250,7 @@
 		authErr := httpResp.Header.Get(authErrorHeader)
 		if len(authErr) > 0 {
 			body.Close()
-			return errors.E(op, errors.Permission, errors.Str(authErr))
+			return errors.E(op, errors.Permission, authErr)
 		}
 		// No authentication token returned, but no error either.
 		// Proceed.
@@ -263,7 +263,7 @@
 		msg, ok := httpResp.Header[authRequestHeader]
 		if !ok {
 			body.Close()
-			return errors.E(op, errors.Permission, errors.Str("proxy server must authenticate"))
+			return errors.E(op, errors.Permission, "proxy server must authenticate")
 		}
 		if err := c.verifyServerUser(msg); err != nil {
 			body.Close()
@@ -277,7 +277,7 @@
 	return nil
 }
 
-func readResponse(op string, body io.ReadCloser, resp pb.Message) error {
+func readResponse(op errors.Op, body io.ReadCloser, resp pb.Message) error {
 	respBytes, err := ioutil.ReadAll(body)
 	body.Close()
 	if err != nil {
@@ -306,7 +306,7 @@
 		return
 	}
 	if ok[0] != 'O' || ok[1] != 'K' {
-		stream.Error(errors.E(errors.IO, errors.Str("unexpected stream preamble")))
+		stream.Error(errors.E(errors.IO, "unexpected stream preamble"))
 		return
 	}
 
diff --git a/vendor/upspin.io/rpc/keyserver/server.go b/vendor/upspin.io/rpc/keyserver/server.go
index 6e9f55e..8b2fdd1 100644
--- a/vendor/upspin.io/rpc/keyserver/server.go
+++ b/vendor/upspin.io/rpc/keyserver/server.go
@@ -131,7 +131,7 @@
 		if errors.Is(errors.NotExist, err) {
 			// The end user doesn't care about the backend
 			// error if it's a "not exist" error.
-			err = errors.E("rpc/keyserver", upspin.UserName(req.UserName), errors.NotExist)
+			err = errors.E(errors.Op("rpc/keyserver"), upspin.UserName(req.UserName), errors.NotExist)
 		}
 		return &proto.KeyLookupResponse{Error: errors.MarshalError(err)}, nil
 	}
diff --git a/vendor/upspin.io/rpc/keyservice.go b/vendor/upspin.io/rpc/keyservice.go
index 22fb89c..48ba9d4 100644
--- a/vendor/upspin.io/rpc/keyservice.go
+++ b/vendor/upspin.io/rpc/keyservice.go
@@ -13,7 +13,7 @@
 // PublicUserKeyService returns a Lookup function that looks up user's public keys.
 // The lookup function returned is bound to a well-known public Upspin user service.
 func PublicUserKeyService(cfg upspin.Config) func(userName upspin.UserName) (upspin.PublicKey, error) {
-	const op = "rpc.PublicUserKeyService"
+	const op errors.Op = "rpc.PublicUserKeyService"
 	return func(userName upspin.UserName) (upspin.PublicKey, error) {
 		key, err := bind.KeyServer(cfg, cfg.KeyEndpoint())
 		if err != nil {
diff --git a/vendor/upspin.io/rpc/server.go b/vendor/upspin.io/rpc/server.go
index 2877237..b4070f6 100644
--- a/vendor/upspin.io/rpc/server.go
+++ b/vendor/upspin.io/rpc/server.go
@@ -259,7 +259,7 @@
 }
 
 func (s *serverImpl) SessionForRequest(w http.ResponseWriter, r *http.Request) (session Session, err error) {
-	const op = "rpc.SessionForRequest"
+	const op errors.Op = "rpc.SessionForRequest"
 
 	defer func() {
 		if err == nil {
@@ -279,20 +279,20 @@
 
 	proxyRequest, ok := r.Header[proxyRequestHeader]
 	if ok && len(proxyRequest) != 1 {
-		return nil, errors.E(errors.Invalid, errors.Str("invalid proxy request in header"))
+		return nil, errors.E(errors.Invalid, "invalid proxy request in header")
 	}
 
 	// Clients send a single header line with comma-separated values.
 	authRequest, ok := r.Header[authRequestHeader]
 	if !ok {
-		return nil, errors.E(errors.Invalid, errors.Str("missing auth request header"))
+		return nil, errors.E(errors.Invalid, "missing auth request header")
 	} else if len(authRequest) == 5 {
 		// Old-style authentication tokens should now fail,
 		// but provide an informative error message when they do.
 		// TODO(adg): Remove this if/else block on April 15.
-		return nil, errors.E(errors.Invalid, errors.Str("invalid auth request header (please update your Upspin clients and servers)"))
+		return nil, errors.E(errors.Invalid, "invalid auth request header (please update your Upspin clients and servers)")
 	} else if len(authRequest) != 1 {
-		return nil, errors.E(errors.Invalid, errors.Str("invalid auth request header"))
+		return nil, errors.E(errors.Invalid, "invalid auth request header")
 	}
 	authRequest = strings.Split(authRequest[0], ",")
 
@@ -301,7 +301,7 @@
 
 func (s *serverImpl) validateToken(authToken string) (Session, error) {
 	if len(authToken) < authTokenEntropyLen {
-		return nil, errors.E(errors.Invalid, errors.Str("invalid auth token"))
+		return nil, errors.E(errors.Invalid, "invalid auth token")
 	}
 
 	// Get the session for this authToken
@@ -430,7 +430,7 @@
 	}
 	f := cfg.Factotum()
 	if f == nil {
-		return nil, errors.E(cfg.UserName(), errors.Str("no factotum available"))
+		return nil, errors.E(cfg.UserName(), "no factotum available")
 	}
 
 	user := string(cfg.UserName())
diff --git a/vendor/upspin.io/serverutil/frontend/frontend.go b/vendor/upspin.io/serverutil/frontend/frontend.go
index 1b3bfe7..60197d6 100644
--- a/vendor/upspin.io/serverutil/frontend/frontend.go
+++ b/vendor/upspin.io/serverutil/frontend/frontend.go
@@ -75,6 +75,7 @@
 	extMarkdown  = ".md"
 	docHostname  = "upspin.io"      // redirect doc requests to this host
 	testHostname = "test.upspin.io" // don't redirect requests to this host
+	augieUser    = "augie@upspin.io"
 )
 
 // sourceRepo is a map from each custom domain to their repo base URLs.
@@ -142,6 +143,7 @@
 	if cfg != nil {
 		mux.Handle(downloadPath, newDownloadHandler(cfg, s.tmpl.download))
 		mux.Handle("/"+releaseUser+"/", web.New(cfg, isWriter(releaseUser)))
+		mux.Handle("/"+augieUser+"/", web.New(cfg, isWriter(augieUser)))
 	}
 	s.handlers = goGetHandler{gziphandler.GzipHandler(canonicalHostHandler{mux})}
 
diff --git a/vendor/upspin.io/serverutil/perm/dir.go b/vendor/upspin.io/serverutil/perm/dir.go
index 5110957..94bba12 100644
--- a/vendor/upspin.io/serverutil/perm/dir.go
+++ b/vendor/upspin.io/serverutil/perm/dir.go
@@ -14,7 +14,7 @@
 // permissions. It will only start polling the store permissions after the
 // ready channel is closed.
 func WrapDir(cfg upspin.Config, ready <-chan struct{}, target upspin.UserName, dir upspin.DirServer) upspin.DirServer {
-	const op = "serverutil/perm.WrapDir"
+	const op errors.Op = "serverutil/perm.WrapDir"
 	p := newPerm(op, cfg, ready, target, dir.Lookup, dir.Watch, noop, retry, nil)
 	return p.WrapDir(dir)
 }
@@ -40,20 +40,20 @@
 
 // Put implements upspin.DirServer.
 func (d *dirWrapper) Put(entry *upspin.DirEntry) (*upspin.DirEntry, error) {
-	const op = "serverutil/perm.Put"
+	const op errors.Op = "serverutil/perm.Put"
 	p, err := path.Parse(entry.Name)
 	if err != nil {
 		return nil, errors.E(op, err)
 	}
 	if p.IsRoot() && !d.perm.IsWriter(d.user) {
-		return nil, errors.E(op, d.user, errors.Permission, errors.Str("user not authorized"))
+		return nil, errors.E(op, d.user, errors.Permission, "user not authorized")
 	}
 	return d.DirServer.Put(entry)
 }
 
 // Dial implements upspin.Service.
 func (d *dirWrapper) Dial(config upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "serverutil/perm.Dial"
+	const op errors.Op = "serverutil/perm.Dial"
 	service, err := d.DirServer.Dial(config, e)
 	if err != nil {
 		return nil, errors.E(op, err)
diff --git a/vendor/upspin.io/serverutil/perm/perm.go b/vendor/upspin.io/serverutil/perm/perm.go
index 129eab8..4b1e7c7 100644
--- a/vendor/upspin.io/serverutil/perm/perm.go
+++ b/vendor/upspin.io/serverutil/perm/perm.go
@@ -68,7 +68,7 @@
 // resolving the DirServer using the given config. The target user is
 // typically the user name of a server, such as a StoreServer or a DirServer.
 func New(cfg upspin.Config, ready <-chan struct{}, target upspin.UserName) *Perm {
-	const op = "serverutil/perm.New"
+	const op errors.Op = "serverutil/perm.New"
 	return newPerm(op, cfg, ready, target, nil, nil, noop, retry, nil)
 }
 
@@ -76,7 +76,7 @@
 // file which must reside on the given DirServer. The target user is typically
 // the user name of a server, such as a StoreServer or a DirServer.
 func NewWithDir(cfg upspin.Config, ready <-chan struct{}, target upspin.UserName, dir upspin.DirServer) *Perm {
-	const op = "serverutil/perm.NewFromDir"
+	const op errors.Op = "serverutil/perm.NewFromDir"
 	return newPerm(op, cfg, ready, target, dir.Lookup, dir.Watch, noop, retry, nil)
 }
 
@@ -90,7 +90,7 @@
 // watch changes on the writers file. If lookup or watch are nil the DirServer
 // is resolved using bind and the given config. The target user is typically
 // the user name of a server, such as a StoreServer or a DirServer.
-func newPerm(op string, cfg upspin.Config, ready <-chan struct{}, target upspin.UserName, lookup lookupFunc, watch watchFunc, onUpdate, onRetry func(), done <-chan struct{}) *Perm {
+func newPerm(op errors.Op, cfg upspin.Config, ready <-chan struct{}, target upspin.UserName, lookup lookupFunc, watch watchFunc, onUpdate, onRetry func(), done <-chan struct{}) *Perm {
 	p := &Perm{
 		cfg:        cfg,
 		targetUser: target,
@@ -117,7 +117,7 @@
 
 // updateLoop continuously watches for updates on WritersGroupFile.
 // It must be run in a goroutine.
-func (p *Perm) updateLoop(op string) {
+func (p *Perm) updateLoop(op errors.Op) {
 	var (
 		events    <-chan upspin.Event
 		accessSeq int64 = -1
diff --git a/vendor/upspin.io/serverutil/perm/store.go b/vendor/upspin.io/serverutil/perm/store.go
index 8a7215a..4eea40a 100644
--- a/vendor/upspin.io/serverutil/perm/store.go
+++ b/vendor/upspin.io/serverutil/perm/store.go
@@ -26,7 +26,7 @@
 // permissions. It will only start polling the store permissions after the
 // ready channel is closed.
 func WrapStore(cfg upspin.Config, ready <-chan struct{}, store upspin.StoreServer) upspin.StoreServer {
-	const op = "serverutil/perm.WrapStore"
+	const op errors.Op = "serverutil/perm.WrapStore"
 	p := newPerm(op, cfg, ready, cfg.UserName(), nil, nil, noop, retry, nil)
 	return p.WrapStore(store)
 }
@@ -51,7 +51,7 @@
 
 // Put implements upspin.StoreServer.
 func (s *storeWrapper) Put(data []byte) (*upspin.Refdata, error) {
-	const op = "store/perm.Put"
+	const op errors.Op = "store/perm.Put"
 
 	if !s.perm.IsWriter(s.user) {
 		return nil, errors.E(op, s.user, errors.Permission, errors.Errorf("user not authorized"))
@@ -61,7 +61,7 @@
 
 // Delete implements upspin.StoreServer.
 func (s *storeWrapper) Delete(ref upspin.Reference) error {
-	const op = "store/perm.Delete"
+	const op errors.Op = "store/perm.Delete"
 
 	if s.perm.targetUser != s.user {
 		return errors.E(op, s.user, errors.Permission, errors.Errorf("user not authorized"))
@@ -71,7 +71,7 @@
 
 // Dial implements upspin.Service.
 func (s *storeWrapper) Dial(cfg upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "store/perm.Dial"
+	const op errors.Op = "store/perm.Dial"
 	service, err := s.StoreServer.Dial(cfg, e)
 	if err != nil {
 		return nil, errors.E(op, err)
diff --git a/vendor/upspin.io/serverutil/signup/signup.go b/vendor/upspin.io/serverutil/signup/signup.go
index 887865a..23bb7f1 100644
--- a/vendor/upspin.io/serverutil/signup/signup.go
+++ b/vendor/upspin.io/serverutil/signup/signup.go
@@ -321,7 +321,7 @@
 	}
 	keyServer, ok := service.(upspin.KeyServer)
 	if !ok {
-		return nil, errors.E(errors.Internal, errors.Str("dialed service not an instance of upspin.KeyServer"))
+		return nil, errors.E(errors.Internal, "dialed service not an instance of upspin.KeyServer")
 	}
 	return keyServer, nil
 }
diff --git a/vendor/upspin.io/serverutil/upspinserver/main.go b/vendor/upspin.io/serverutil/upspinserver/main.go
index 8120adb..70ea5e7 100644
--- a/vendor/upspin.io/serverutil/upspinserver/main.go
+++ b/vendor/upspin.io/serverutil/upspinserver/main.go
@@ -172,17 +172,27 @@
 }
 
 // fmtStoreConfig formats a ServerConfig.StoreConfig value as a string,
-// ommitting any privateKeyData fields as they include sensitive information.
+// omitting any fields that may include sensitive information.
 func fmtStoreConfig(cfg []string) string {
 	var out []string
 	for _, s := range cfg {
-		if !strings.HasPrefix(s, "privateKeyData=") {
+		if !containsAny(s, "appkey", "token", "private") {
 			out = append(out, s)
 		}
 	}
 	return strings.Join(out, " ")
 }
 
+func containsAny(s string, lowerCaseNeedles ...string) bool {
+	ls := strings.ToLower(s)
+	for _, n := range lowerCaseNeedles {
+		if strings.Contains(ls, n) {
+			return true
+		}
+	}
+	return false
+}
+
 type setupHandler struct {
 	mu   sync.Mutex
 	done bool
diff --git a/vendor/upspin.io/store/inprocess/store.go b/vendor/upspin.io/store/inprocess/store.go
index 13d4e84..c0ec9ee 100644
--- a/vendor/upspin.io/store/inprocess/store.go
+++ b/vendor/upspin.io/store/inprocess/store.go
@@ -72,7 +72,7 @@
 
 // Delete implements upspin.StoreServer
 func (s *service) Delete(ref upspin.Reference) error {
-	const op = "store/inprocess.Delete"
+	const op errors.Op = "store/inprocess.Delete"
 	s.data.mu.Lock()
 	defer s.data.mu.Unlock()
 	_, ok := s.data.blob[ref]
@@ -93,9 +93,9 @@
 // Get implements upspin.StoreServer
 // TODO: Get should provide alternate location if missing.
 func (s *service) Get(ref upspin.Reference) (ciphertext []byte, refdata *upspin.Refdata, other []upspin.Location, err error) {
-	const op = "store/inprocess.Get"
+	const op errors.Op = "store/inprocess.Get"
 	if ref == "" {
-		return nil, nil, nil, errors.E(op, errors.Invalid, errors.Str("empty reference"))
+		return nil, nil, nil, errors.E(op, errors.Invalid, "empty reference")
 	}
 	s.data.mu.Lock()
 	data, ok := s.data.blob[ref]
@@ -104,7 +104,7 @@
 		return nil, nil, nil, errors.E(op, errors.NotExist, errors.Errorf("no such blob: %s", ref))
 	}
 	if upspin.Reference(sha256key.Of(data).String()) != ref {
-		return nil, nil, nil, errors.E(op, errors.Invalid, errors.Str("internal hash mismatch in StoreServer.Get"))
+		return nil, nil, nil, errors.E(op, errors.Invalid, "internal hash mismatch in StoreServer.Get")
 	}
 	refdata = &upspin.Refdata{
 		Reference: ref,
@@ -119,9 +119,9 @@
 // Dial ignores the address within the endpoint but requires that the transport be InProcess.
 // TODO: Authenticate the caller.
 func (s *service) Dial(config upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "store/inprocess.Dial"
+	const op errors.Op = "store/inprocess.Dial"
 	if e.Transport != upspin.InProcess {
-		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, errors.E(op, errors.Invalid, "unrecognized transport")
 	}
 	s.data.mu.Lock()
 	defer s.data.mu.Unlock()
diff --git a/vendor/upspin.io/store/remote/remote.go b/vendor/upspin.io/store/remote/remote.go
index 417dbfc..9301ab3 100644
--- a/vendor/upspin.io/store/remote/remote.go
+++ b/vendor/upspin.io/store/remote/remote.go
@@ -219,13 +219,13 @@
 func (r *remote) opf(method string, format string, args ...interface{}) *operation {
 	ep := r.cfg.endpoint.String()
 	s := fmt.Sprintf("store/remote: %q: store.%s", ep, method)
-	op := &operation{s, fmt.Sprintf(format, args...)}
+	op := &operation{errors.Op(s), fmt.Sprintf(format, args...)}
 	log.Debug.Print(op)
 	return op
 }
 
 type operation struct {
-	op   string
+	op   errors.Op
 	args string
 }
 
diff --git a/vendor/upspin.io/store/server/server.go b/vendor/upspin.io/store/server/server.go
index 01d0c55..f50afd1 100644
--- a/vendor/upspin.io/store/server/server.go
+++ b/vendor/upspin.io/store/server/server.go
@@ -32,7 +32,7 @@
 
 // New returns a StoreServer that serves the given endpoint with the provided options.
 func New(options ...string) (upspin.StoreServer, error) {
-	const op = "store/server.New"
+	const op errors.Op = "store/server.New"
 
 	var backend string
 	var dialOpts []storage.DialOpts
@@ -46,7 +46,7 @@
 		dialOpts = append(dialOpts, storage.WithOptions(option))
 	}
 	if backend == "" {
-		return nil, errors.E(op, errors.Invalid, errors.Str(`storage "backend" option is missing`))
+		return nil, errors.E(op, errors.Invalid, `storage "backend" option is missing`)
 	}
 	s, err := storage.Dial(backend, dialOpts...)
 	if err != nil {
@@ -59,7 +59,7 @@
 
 // Put implements upspin.StoreServer.
 func (s *server) Put(data []byte) (*upspin.Refdata, error) {
-	const op = "store/server.Put"
+	const op errors.Op = "store/server.Put"
 
 	m, sp := metric.NewSpan(op)
 	sp.SetAnnotation(fmt.Sprintf("size=%d", len(data)))
@@ -81,7 +81,7 @@
 
 // Get implements upspin.StoreServer.
 func (s *server) Get(ref upspin.Reference) ([]byte, *upspin.Refdata, []upspin.Location, error) {
-	const op = "store/server.Get"
+	const op errors.Op = "store/server.Get"
 
 	m, sp := metric.NewSpan(op)
 	defer m.Done()
@@ -123,7 +123,7 @@
 
 // Delete implements upspin.StoreServer.
 func (s *server) Delete(ref upspin.Reference) error {
-	const op = "store/server.Delete"
+	const op errors.Op = "store/server.Delete"
 
 	m, _ := metric.NewSpan(op)
 	defer m.Done()
diff --git a/vendor/upspin.io/store/unassigned/unassigned.go b/vendor/upspin.io/store/unassigned/unassigned.go
index 425a609..e351afc 100644
--- a/vendor/upspin.io/store/unassigned/unassigned.go
+++ b/vendor/upspin.io/store/unassigned/unassigned.go
@@ -22,19 +22,19 @@
 
 // Get implements upspin.StoreServer.Get.
 func (Server) Get(ref upspin.Reference) ([]byte, *upspin.Refdata, []upspin.Location, error) {
-	const op = "store/Server.Get"
+	const op errors.Op = "store/Server.Get"
 	return nil, nil, nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
 // Put implements upspin.StoreServer.Put.
 func (Server) Put(data []byte) (*upspin.Refdata, error) {
-	const op = "store/Server.Put"
+	const op errors.Op = "store/Server.Put"
 	return nil, errors.E(op, errors.Invalid, unassignedErr)
 }
 
 // Delete implements upspin.StoreServer.Delete.
 func (Server) Delete(ref upspin.Reference) error {
-	const op = "store/Server.Delete"
+	const op errors.Op = "store/Server.Delete"
 	return errors.E(op, errors.Invalid, unassignedErr)
 }
 
@@ -49,9 +49,9 @@
 
 // Dial implements upspin.Service.
 func (Server) Dial(config upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
-	const op = "store/Server.Dial"
+	const op errors.Op = "store/Server.Dial"
 	if e.Transport != upspin.Unassigned {
-		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
+		return nil, errors.E(op, errors.Invalid, "unrecognized transport")
 	}
 
 	return Server{e}, nil
diff --git a/vendor/upspin.io/upspin/proto/proto.go b/vendor/upspin.io/upspin/proto/proto.go
index 65e5a17..ae03257 100644
--- a/vendor/upspin.io/upspin/proto/proto.go
+++ b/vendor/upspin.io/upspin/proto/proto.go
@@ -66,7 +66,7 @@
 // UpspinDirEntry converts a slice of bytes struct to *upspin.DirEntry.
 // If the slice is nil or empty, it returns nil.
 func UpspinDirEntry(b []byte) (*upspin.DirEntry, error) {
-	const op = "proto.UpspinDirEntry"
+	const op errors.Op = "proto.UpspinDirEntry"
 	if len(b) == 0 {
 		return nil, nil
 	}
@@ -76,7 +76,7 @@
 		return nil, err
 	}
 	if len(b) != 0 {
-		return nil, errors.E(op, errors.Invalid, errors.Str("extra data"))
+		return nil, errors.E(op, errors.Invalid, "extra data")
 	}
 	return &d, nil
 }
diff --git a/vendor/upspin.io/user/user.go b/vendor/upspin.io/user/user.go
index c6f54f5..ce50453 100644
--- a/vendor/upspin.io/user/user.go
+++ b/vendor/upspin.io/user/user.go
@@ -62,10 +62,10 @@
 // follow the "ignore" rules.
 //
 func Parse(userName upspin.UserName) (user, suffix, domain string, err error) {
-	const op = "user.Parse"
+	const op = errors.Op("user.Parse")
 	name := string(userName)
 	if len(userName) >= 254 {
-		return "", "", "", errors.E(op, errors.Invalid, userName, errors.Str("name too long"))
+		return "", "", "", errors.E(op, errors.Invalid, userName, "name too long")
 	}
 	if strings.Count(name, "@") != 1 {
 		return "", "", "", errors.E(op, errors.Invalid, userName, errors.Str("user name must contain one @ symbol"))
@@ -92,12 +92,12 @@
 // documentation for Parse except that "*" is not a valid user and the user name
 // itself must be less than 255 bytes long.
 func ParseUser(user string) (userName, suffix string, err error) {
-	return parseUser("user.ParseUser", upspin.UserName(user), user)
+	return parseUser(errors.Op("user.ParseUser"), upspin.UserName(user), user)
 }
 
 // parseUser is the implementation of ParseUser, also called by Parse.
 // It takes the full UserName as well as the user component, to aid in error reporting.
-func parseUser(op string, userName upspin.UserName, user string) (string, string, error) {
+func parseUser(op errors.Op, userName upspin.UserName, user string) (string, string, error) {
 	if len(user) >= 255 {
 		return errParseUser(op, userName, "user name too long")
 	}
@@ -141,12 +141,12 @@
 // documentation for Parse except the domain name itself must be less than 255
 // bytes long.
 func ParseDomain(domain string) (string, error) {
-	return parseDomain("user.ParseDomain", upspin.UserName(domain), domain)
+	return parseDomain(errors.Op("user.ParseDomain"), upspin.UserName(domain), domain)
 }
 
 // parseDomain is the implementation of ParseDomain, also called by Parse.
 // It takes the full UserName as well as the domain component, to aid in error reporting.
-func parseDomain(op string, userName upspin.UserName, domain string) (string, error) {
+func parseDomain(op errors.Op, userName upspin.UserName, domain string) (string, error) {
 	if len(domain) >= 255 {
 		return errParseDomain(op, userName, "domain name too long")
 	}
@@ -189,12 +189,12 @@
 	return domain, nil
 }
 
-func errParseUser(op string, userName upspin.UserName, msg string) (u, s string, err error) {
-	return "", "", errors.E(op, errors.Invalid, userName, errors.Str(msg))
+func errParseUser(op errors.Op, userName upspin.UserName, msg string) (u, s string, err error) {
+	return "", "", errors.E(op, errors.Invalid, userName, msg)
 }
 
-func errParseDomain(op string, userName upspin.UserName, msg string) (d string, err error) {
-	return "", errors.E(op, errors.Invalid, userName, errors.Str(msg))
+func errParseDomain(op errors.Op, userName upspin.UserName, msg string) (d string, err error) {
+	return "", errors.E(op, errors.Invalid, userName, msg)
 }
 
 func canonicalize(user string) (string, error) {
diff --git a/vendor/upspin.io/valid/valid.go b/vendor/upspin.io/valid/valid.go
index 7df4d25..d793088 100644
--- a/vendor/upspin.io/valid/valid.go
+++ b/vendor/upspin.io/valid/valid.go
@@ -20,23 +20,23 @@
 // UserName verifies that the name is a syntactically valid user's email address.
 // It also requires that the domain name be lower-cased to avoid ambiguity.
 func UserName(userName upspin.UserName) error {
-	const op = "valid.UserName"
+	const op errors.Op = "valid.UserName"
 	u, _, d, err := user.Parse(userName)
 	if err != nil {
 		return errors.E(op, err)
 	}
 	if string(userName) != u+"@"+d {
-		return errors.E(op, errors.Invalid, userName, errors.Str("not canonically formatted"))
+		return errors.E(op, errors.Invalid, userName, "not canonically formatted")
 	}
 	if userName == access.AllUsers {
-		return errors.E(op, errors.Invalid, userName, errors.Str("reserved user name"))
+		return errors.E(op, errors.Invalid, userName, "reserved user name")
 	}
 	return nil
 }
 
 // User verifies that the User struct is valid, that is, that all its fields are syntactically valid.
 func User(user *upspin.User) error {
-	const op = "valid.User"
+	const op errors.Op = "valid.User"
 	if err := UserName(user.Name); err != nil {
 		return errors.E(op, errors.Invalid, err)
 	}
@@ -71,7 +71,7 @@
 // DirBlock verifies that the block is valid, that is, that it has a
 // greater-than-zero Size, non-negative Offset, and valid Location.
 func DirBlock(block upspin.DirBlock) error {
-	const op = "valid.DirBlock"
+	const op errors.Op = "valid.DirBlock"
 	if block.Size <= 0 {
 		return errors.E(op, errors.Invalid, errors.Errorf("non-positive block size %d", block.Size))
 	}
@@ -90,7 +90,7 @@
 // Endpoint verifies that the endpoint looks syntactically valid. It does not check that the
 // endpoint defines a reachable server.
 func Endpoint(endpoint upspin.Endpoint) error {
-	const op = "valid.Endpoint"
+	const op errors.Op = "valid.Endpoint"
 	switch endpoint.Transport {
 	case upspin.InProcess:
 		// OK if there is a netaddr, or not.
@@ -122,19 +122,19 @@
 // - Sequence must have a known special value or be non-negative
 // - for non-directory entries, a Writer field is required.
 func DirEntry(entry *upspin.DirEntry) error {
-	const op = "valid.DirEntry"
+	const op errors.Op = "valid.DirEntry"
 	// SignedName must be good.
 	if err := validPathName(entry.SignedName); err != nil {
 		return errors.E(op, errors.Invalid, entry.SignedName, err)
 	}
 	// Name must match.
 	if entry.Name != entry.SignedName {
-		return errors.E(op, errors.Invalid, entry.Name, errors.Str("Name and SignedName must match"))
+		return errors.E(op, errors.Invalid, entry.Name, "Name and SignedName must match")
 	}
 	// Is the entry incomplete? Servers must not accept such entries.
 	// (Although they may return them.)
 	if entry.IsIncomplete() {
-		return errors.E(op, errors.Invalid, entry.Name, errors.Str("entry must not be incomplete"))
+		return errors.E(op, errors.Invalid, entry.Name, "entry must not be incomplete")
 	}
 
 	// Attribute must be valid and consistent with entry.
@@ -151,12 +151,12 @@
 
 	// Blocks only for AttrNone
 	if entry.Attr != upspin.AttrNone && len(entry.Blocks) > 0 {
-		return errors.E(op, errors.Invalid, entry.Name, errors.Str("link or directory cannot have data"))
+		return errors.E(op, errors.Invalid, entry.Name, "link or directory cannot have data")
 	}
 
 	// Link only for AttrLink
 	if entry.Attr != upspin.AttrLink && entry.Link != "" {
-		return errors.E(op, errors.Invalid, entry.Name, errors.Str("only links can have Link set"))
+		return errors.E(op, errors.Invalid, entry.Name, "only links can have Link set")
 	}
 
 	// Packing must be valid.
@@ -180,7 +180,7 @@
 	offset := int64(0)
 	for _, block := range entry.Blocks {
 		if block.Offset != offset {
-			return errors.E(op, errors.Invalid, entry.Name, errors.Str("data blocks are not contiguous"))
+			return errors.E(op, errors.Invalid, entry.Name, "data blocks are not contiguous")
 		}
 		offset += block.Size
 		if err := DirBlock(block); err != nil {
@@ -192,7 +192,7 @@
 		return nil
 	}
 	if err := UserName(entry.Writer); err != nil {
-		return errors.E(op, errors.Str("invalid writer"), err)
+		return errors.E(op, "invalid writer", err)
 	}
 	return nil
 }
@@ -202,9 +202,9 @@
 // printable, the replacement rune (U+FFFD) is considered invalid, even if it is explicitly
 // present, as it usually indicates erroneous UTF-8 or Unicode.
 func Reference(ref upspin.Reference) error {
-	const op = "valid.Reference"
+	const op errors.Op = "valid.Reference"
 	if ref == "" {
-		return errors.E(op, errors.Invalid, errors.Str("empty reference"))
+		return errors.E(op, errors.Invalid, "empty reference")
 	}
 	previ := 0
 	for i, r := range ref {