// while constructing a build list. BuildListError prints the chain
 // of requirements to the module where the error occurred.
 type BuildListError struct {
-       Err   error
-       Stack []module.Version
+       err   error
+       stack []buildListErrorElem
+}
+
+type buildListErrorElem struct {
+       m module.Version
+
+       // nextReason is the reason this module depends on the next module in the
+       // stack. Typically either "requires", or "upgraded to".
+       nextReason string
 }
 
 func (e *BuildListError) Error() string {
        b := &strings.Builder{}
-       errMsg := e.Err.Error()
-       stack := e.Stack
+       errMsg := e.err.Error()
+       stack := e.stack
 
        // Don't print modules at the beginning of the chain without a
        // version. These always seem to be the main module or a
        // synthetic module ("target@").
-       for len(stack) > 0 && stack[len(stack)-1].Version == "" {
+       for len(stack) > 0 && stack[len(stack)-1].m.Version == "" {
                stack = stack[:len(stack)-1]
        }
 
        // Don't print the last module if the error message already
        // starts with module path and version.
-       if len(stack) > 0 && strings.HasPrefix(errMsg, fmt.Sprintf("%s@%s: ", stack[0].Path, stack[0].Version)) {
-               // error already mentions module
-               stack = stack[1:]
+       errMentionsLast := len(stack) > 0 && strings.HasPrefix(errMsg, fmt.Sprintf("%s@%s: ", stack[0].m.Path, stack[0].m.Version))
+       for i := len(stack) - 1; i >= 1; i-- {
+               fmt.Fprintf(b, "%s@%s %s\n\t", stack[i].m.Path, stack[i].m.Version, stack[i].nextReason)
        }
-
-       for i := len(stack) - 1; i >= 0; i-- {
-               fmt.Fprintf(b, "%s@%s ->\n\t", stack[i].Path, stack[i].Version)
+       if errMentionsLast || len(stack) == 0 {
+               b.WriteString(errMsg)
+       } else {
+               fmt.Fprintf(b, "%s@%s: %s", stack[0].m.Path, stack[0].m.Version, errMsg)
        }
-       b.WriteString(errMsg)
        return b.String()
 }
 
                        q = q[1:]
 
                        if node.err != nil {
-                               err := &BuildListError{Err: node.err}
-                               for n := node; n != nil; n = neededBy[n] {
-                                       err.Stack = append(err.Stack, n.m)
+                               err := &BuildListError{
+                                       err:   node.err,
+                                       stack: []buildListErrorElem{{m: node.m}},
+                               }
+                               for n, prev := neededBy[node], node; n != nil; n, prev = neededBy[n], n {
+                                       reason := "requires"
+                                       if n.upgrade == prev.m {
+                                               reason = "updating to"
+                                       }
+                                       err.stack = append(err.stack, buildListErrorElem{m: n.m, nextReason: reason})
                                }
                                return nil, err
                        }
 
 go mod download example.com/badchain/b@v1.1.0
 go mod download example.com/badchain/c@v1.1.0
 
-# Try to upgrade example.com/badchain/a (and its dependencies).
+# Try to update example.com/badchain/a (and its dependencies).
 ! go get -u example.com/badchain/a
-cmp stderr upgrade-a-expected
+cmp stderr update-a-expected
 cmp go.mod go.mod.orig
 
-# Try to upgrade the main module. This upgrades everything, including
+# Try to update the main module. This updates everything, including
 # modules that aren't direct requirements, so the error stack is shorter.
 ! go get -u
-cmp stderr upgrade-main-expected
+cmp stderr update-main-expected
 cmp go.mod go.mod.orig
 
-# Upgrade manually. Listing modules should produce an error.
+# update manually. Listing modules should produce an error.
 go mod edit -require=example.com/badchain/a@v1.1.0
 ! go list -m
 cmp stderr list-expected
 module m
 
 require example.com/badchain/a v1.0.0
--- upgrade-main-expected --
-go get: example.com/badchain/c@v1.0.0 ->
+-- update-main-expected --
+go get: example.com/badchain/c@v1.0.0 updating to
        example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"
--- upgrade-a-expected --
-go get: example.com/badchain/a@v1.1.0 ->
-       example.com/badchain/b@v1.1.0 ->
+-- update-a-expected --
+go get: example.com/badchain/a@v1.1.0 requires
+       example.com/badchain/b@v1.1.0 requires
        example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"
 -- list-expected --
-go: example.com/badchain/a@v1.1.0 ->
-       example.com/badchain/b@v1.1.0 ->
+go: example.com/badchain/a@v1.1.0 requires
+       example.com/badchain/b@v1.1.0 requires
        example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"