diff --git a/cmd/fileTransfer.go b/cmd/fileTransfer.go
index d383011b1f715c22863e46e7b3cc361ede00feb6..04214377d23c0fdbf6642159888cb65c933f0e9f 100644
--- a/cmd/fileTransfer.go
+++ b/cmd/fileTransfer.go
@@ -93,11 +93,11 @@ var ftCmd = &cobra.Command{
 		for done := false; !done; {
 			select {
 			case <-sendDone:
-				jww.DEBUG.Printf("[FT] Finished sending file. Stopping " +
+				jww.INFO.Printf("[FT] Finished sending file. Stopping " +
 					"threads and network follower.")
 				done = true
 			case <-receiveDone:
-				jww.DEBUG.Printf("[FT] Finished receiving file. Stopping " +
+				jww.INFO.Printf("[FT] Finished receiving file. Stopping " +
 					"threads and network follower.")
 				done = true
 			}
@@ -109,10 +109,10 @@ var ftCmd = &cobra.Command{
 		// Stop network follower
 		err = client.StopNetworkFollower()
 		if err != nil {
-			jww.WARN.Printf("[FT] "+"Failed to stop network follower: %+v", err)
+			jww.WARN.Printf("[FT] Failed to stop network follower: %+v", err)
 		}
 
-		jww.DEBUG.Print("[FT] File transfer finished stopping threads and " +
+		jww.INFO.Print("[FT] File transfer finished stopping threads and " +
 			"network follower.")
 	},
 }
@@ -151,13 +151,14 @@ func initFileTransferManager(client *api.Client, maxThroughput int) (
 	// Create new manager
 	manager, err := ft.NewManager(client, receiveCB, p)
 	if err != nil {
-		jww.FATAL.Panicf("Failed to create new file transfer manager: %+v", err)
+		jww.FATAL.Panicf(
+			"[FT] Failed to create new file transfer manager: %+v", err)
 	}
 
 	// Start the file transfer sending and receiving threads
 	err = client.AddService(manager.StartProcesses)
 	if err != nil {
-		jww.FATAL.Panicf("Failed to start file transfer threads: %+v", err)
+		jww.FATAL.Panicf("[FT] Failed to start file transfer threads: %+v", err)
 	}
 
 	return manager, receiveChan
@@ -171,7 +172,7 @@ func sendFile(filePath, fileType, filePreviewPath, filePreviewString,
 	// Get file from path
 	fileData, err := utils.ReadFile(filePath)
 	if err != nil {
-		jww.FATAL.Panicf("Failed to read file %q: %+v", filePath, err)
+		jww.FATAL.Panicf("[FT] Failed to read file %q: %+v", filePath, err)
 	}
 
 	// Get file preview from path
@@ -179,7 +180,7 @@ func sendFile(filePath, fileType, filePreviewPath, filePreviewString,
 	if filePreviewPath != "" {
 		filePreviewData, err = utils.ReadFile(filePreviewPath)
 		if err != nil {
-			jww.FATAL.Panicf("Failed to read file preview %q: %+v",
+			jww.FATAL.Panicf("[FT] Failed to read file preview %q: %+v",
 				filePreviewPath, err)
 		}
 	}
@@ -193,15 +194,15 @@ func sendFile(filePath, fileType, filePreviewPath, filePreviewString,
 	// Get recipient contact from file
 	recipient := getContactFromFile(recipientContactPath)
 
-	jww.DEBUG.Printf("[FT] Sending file %q to recipient %s: "+
-		"{size: %d, type: %q, path: %q, previewPath: %q, preview: %q}",
-		fileName, recipient.ID, len(fileData), fileType, filePath,
+	jww.INFO.Printf("[FT] Going to start sending file %q to %s {type: %q, "+
+		"size: %d, retry: %f, path: %q, previewPath: %q, preview: %q}",
+		fileName, recipient.ID, fileType, len(fileData), retry, filePath,
 		filePreviewPath, filePreviewData)
 
 	// Create sent progress callback that prints the results
 	progressCB := func(completed bool, sent, arrived, total uint16,
 		t interfaces.FilePartTracker, err error) {
-		jww.DEBUG.Printf("[FT] Sent progress callback for %q "+
+		jww.INFO.Printf("[FT] Sent progress callback for %q "+
 			"{completed: %t, sent: %d, arrived: %d, total: %d, err: %v}",
 			fileName, completed, sent, arrived, total, err)
 		if (sent == 0 && arrived == 0) || (arrived == total) || completed ||
@@ -221,28 +222,32 @@ func sendFile(filePath, fileType, filePreviewPath, filePreviewString,
 	}
 
 	// Send the file
-	_, err = m.Send(fileName, fileType, fileData, recipient.ID, retry,
+	tid, err := m.Send(fileName, fileType, fileData, recipient.ID, retry,
 		filePreviewData, progressCB, callbackPeriod)
 	if err != nil {
-		jww.FATAL.Panicf("Failed to send file %q to %s: %+v",
+		jww.FATAL.Panicf("[FT] Failed to send file %q to %s: %+v",
 			fileName, recipient.ID, err)
 	}
+
+	jww.INFO.Printf("[FT] Sending new file transfer %s to %s {name: %s, "+
+		"type: %q, size: %d, retry: %f}",
+		tid, recipient, fileName, fileType, len(fileData), retry)
 }
 
 // receiveNewFileTransfers waits to receive new file transfers and prints its
 // information to the log.
 func receiveNewFileTransfers(receive chan receivedFtResults, done,
 	quit chan struct{}, m *ft.Manager) {
-	jww.DEBUG.Print("[FT] Starting thread waiting to receive NewFileTransfer " +
+	jww.INFO.Print("[FT] Starting thread waiting to receive NewFileTransfer " +
 		"E2E message.")
 	for {
 		select {
 		case <-quit:
-			jww.DEBUG.Print("[FT] Quitting thread waiting for NewFileTransfer " +
+			jww.INFO.Print("[FT] Quitting thread waiting for NewFileTransfer " +
 				"E2E message.")
 			return
 		case r := <-receive:
-			jww.DEBUG.Printf("[FT] Received new file %q transfer %s of type "+
+			jww.INFO.Printf("[FT] Received new file %q transfer %s of type "+
 				"%q from %s of size %d bytes with preview: %q",
 				r.fileName, r.tid, r.fileType, r.sender, r.size, r.preview)
 			fmt.Printf("Received new file transfer %q of size %d "+
@@ -251,8 +256,8 @@ func receiveNewFileTransfers(receive chan receivedFtResults, done,
 			cb := newReceiveProgressCB(r.tid, done, m)
 			err := m.RegisterReceivedProgressCallback(r.tid, cb, callbackPeriod)
 			if err != nil {
-				jww.FATAL.Panicf("Failed to register new receive progress "+
-					"callback for transfer %s: %+v", r.tid, err)
+				jww.FATAL.Panicf("[FT] Failed to register new receive "+
+					"progress callback for transfer %s: %+v", r.tid, err)
 			}
 		}
 	}
@@ -264,7 +269,7 @@ func newReceiveProgressCB(tid ftCrypto.TransferID, done chan struct{},
 	m *ft.Manager) interfaces.ReceivedProgressCallback {
 	return func(completed bool, received, total uint16,
 		t interfaces.FilePartTracker, err error) {
-		jww.DEBUG.Printf("[FT] Receive progress callback for transfer %s "+
+		jww.INFO.Printf("[FT] Receive progress callback for transfer %s "+
 			"{completed: %t, received: %d, total: %d, err: %v}",
 			tid, completed, received, total, err)
 
@@ -277,7 +282,8 @@ func newReceiveProgressCB(tid ftCrypto.TransferID, done chan struct{},
 		if completed {
 			receivedFile, err2 := m.Receive(tid)
 			if err2 != nil {
-				jww.FATAL.Panicf("Failed to receive file %s: %+v", tid, err)
+				jww.FATAL.Panicf(
+					"[FT] Failed to receive file %s: %+v", tid, err)
 			}
 			fmt.Printf("Completed receiving file:\n%s\n", receivedFile)
 			done <- struct{}{}
diff --git a/fileTransfer/manager.go b/fileTransfer/manager.go
index 4ac4c1ab75b820edfc7e390a3a14bc69f1fc6036..56e2a21fc023e69faf66bdb77d28ce2ad65df931 100644
--- a/fileTransfer/manager.go
+++ b/fileTransfer/manager.go
@@ -158,6 +158,9 @@ func newManager(client *api.Client, store *storage.Session,
 		return nil, errors.Errorf(newManagerReceivedErr, err)
 	}
 
+	jww.DEBUG.Printf(""+
+		"[FT] Created mew file transfer manager with params: %+v", p)
+
 	return &Manager{
 		receiveCB:             receiveCB,
 		sent:                  sent,
@@ -301,21 +304,21 @@ func (m Manager) Send(fileName, fileType string, fileData []byte,
 
 	// Add the transfer to storage
 	rng = m.rng.GetStream()
-	transferID, err := m.sent.AddTransfer(
+	tid, err := m.sent.AddTransfer(
 		recipient, transferKey, parts, numFps, progressCB, period, rng)
 	if err != nil {
 		return ftCrypto.TransferID{}, err
 	}
 	rng.Close()
 
-	jww.DEBUG.Printf("[FT] Sending new file transfer %q to %s {parts: %d, "+
-		"size: %d, type: %q, ID: %s}",
-		fileName, recipient, numParts, fileSize, fileType, transferID)
+	jww.DEBUG.Printf("[FT] Sending new file transfer %s to %s {name: %s, "+
+		"type: %q, size: %d, parts: %d, numFps: %d, retry: %f}",
+		tid, recipient, fileName, fileType, fileSize, numParts, numFps, retry)
 
 	// Add all parts to queue
-	m.queueParts(transferID, makeListOfPartNums(numParts))
+	m.queueParts(tid, makeListOfPartNums(numParts))
 
-	return transferID, nil
+	return tid, nil
 }
 
 // RegisterSentProgressCallback adds the sent progress callback to the sent
@@ -365,21 +368,21 @@ func (m Manager) Resend(tid ftCrypto.TransferID) error {
 // error if the transfer has not run out of retries.
 func (m Manager) CloseSend(tid ftCrypto.TransferID) error {
 	// Get the transfer for the given ID
-	transfer, err := m.sent.GetTransfer(tid)
+	st, err := m.sent.GetTransfer(tid)
 	if err != nil {
 		return err
 	}
 
 	// Check if the transfer has completed or run out of fingerprints, which
 	// occurs when the retry limit is reached
-	completed, _, _, _, _ := transfer.GetProgress()
-	if transfer.GetNumAvailableFps() > 0 && !completed {
+	completed, _, _, _, _ := st.GetProgress()
+	if st.GetNumAvailableFps() > 0 && !completed {
 		return errors.Errorf(transferInProgressErr, tid)
 	}
 
-	jww.DEBUG.Printf("[FT] Closing file transfer %s sent to %s "+
-		"{completed: %t, parts: %d}",
-		tid, transfer.GetRecipient(), completed, transfer.GetNumParts())
+	jww.DEBUG.Printf("[FT] Closing file transfer %s to %s {completed: %t, "+
+		"parts: %d, numFps: %d/%d,}", tid, st.GetRecipient(), completed,
+		st.GetNumParts(), st.GetNumFps()-st.GetNumAvailableFps(), st.GetNumFps())
 
 	// Delete the transfer from storage
 	return m.sent.DeleteTransfer(tid)
@@ -391,17 +394,21 @@ func (m Manager) CloseSend(tid ftCrypto.TransferID) error {
 // verified, or if the transfer cannot be found.
 func (m Manager) Receive(tid ftCrypto.TransferID) ([]byte, error) {
 	// Get the transfer for the given ID
-	transfer, err := m.received.GetTransfer(tid)
+	rt, err := m.received.GetTransfer(tid)
 	if err != nil {
 		return nil, err
 	}
 
 	// Get the file from the transfer
-	file, err := transfer.GetFile()
+	file, err := rt.GetFile()
 	if err != nil {
 		return nil, err
 	}
 
+	jww.DEBUG.Printf("[FT] Receiver completed transfer %s {size: %d, "+
+		"parts: %d, numFps: %d/%d}", tid, rt.GetFileSize(), rt.GetNumParts(),
+		rt.GetNumFps()-rt.GetNumAvailableFps(), rt.GetNumFps())
+
 	// Return the file and delete the transfer from storage
 	return file, m.received.DeleteTransfer(tid)
 }
diff --git a/fileTransfer/receive.go b/fileTransfer/receive.go
index 020f21bf39e6bce001c4f0951851578e28d21038..c1974176d183aed4ff24f9777d35e78d7f9b1753 100644
--- a/fileTransfer/receive.go
+++ b/fileTransfer/receive.go
@@ -41,7 +41,7 @@ func (m *Manager) receive(rawMsgs chan message.Receive, stop *stoppable.Single)
 				// which means this message is not of the correct type and will
 				// be ignored
 				if strings.Contains(err.Error(), "fingerprint") {
-					jww.INFO.Printf("[FT] %+v", err)
+					jww.TRACE.Printf("[FT] %+v", err)
 				} else {
 					jww.WARN.Printf("[FT] %+v", err)
 				}
@@ -68,15 +68,23 @@ func (m *Manager) readMessage(msg message.Receive) (format.Message, error) {
 	}
 
 	// Add part to received transfer
-	transfer, _, err := m.received.AddPart(partMsg.getPart(),
+	rt, tid, completed, err := m.received.AddPart(partMsg.getPart(),
 		partMsg.getPadding(), cMixMsg.GetMac(), partMsg.getPartNum(),
 		cMixMsg.GetKeyFP())
 	if err != nil {
 		return cMixMsg, err
 	}
 
+	// Print debug message on completion
+	if completed {
+		jww.DEBUG.Printf("[FT] Received last part for file transfer %s from "+
+			"%s {size: %d, parts: %d, numFps: %d/%d}", tid, msg.Sender,
+			rt.GetFileSize(), rt.GetNumParts(),
+			rt.GetNumFps()-rt.GetNumAvailableFps(), rt.GetNumFps())
+	}
+
 	// Call callback with updates
-	transfer.CallProgressCB(nil)
+	rt.CallProgressCB(nil)
 
 	return cMixMsg, nil
 }
diff --git a/fileTransfer/receiveNew.go b/fileTransfer/receiveNew.go
index 4aadd9d3341f1b5056c45bb01124a3941eb5574b..67f3ce3e44570f4f6647c69b7ba098f965b19c62 100644
--- a/fileTransfer/receiveNew.go
+++ b/fileTransfer/receiveNew.go
@@ -37,14 +37,14 @@ func (m *Manager) receiveNewFileTransfer(rawMsgs chan message.Receive,
 			stop.ToStopped()
 			return
 		case receivedMsg := <-rawMsgs:
-			jww.DEBUG.Print(
+			jww.TRACE.Print(
 				"[FT] New file transfer message thread received message.")
 
 			tid, fileName, fileType, sender, size, preview, err :=
 				m.readNewFileTransferMessage(receivedMsg)
 			if err != nil {
 				if err.Error() == receiveMessageTypeErr {
-					jww.INFO.Printf("[FT] Failed to read message as new file "+
+					jww.DEBUG.Printf("[FT] Failed to read message as new file "+
 						"transfer message: %+v", err)
 				} else {
 					jww.WARN.Printf("[FT] Failed to read message as new file "+
@@ -83,10 +83,6 @@ func (m *Manager) readNewFileTransferMessage(msg message.Receive) (
 		return
 	}
 
-	jww.DEBUG.Printf("[FT] Received new file transfer %q from %s {parts: %d, "+
-		"size: %d, type: %q}",
-		newFT.FileName, msg.Sender, newFT.NumParts, newFT.Size, newFT.FileType)
-
 	// Get RNG from stream
 	rng := m.rng.GetStream()
 	defer rng.Close()
@@ -101,6 +97,10 @@ func (m *Manager) readNewFileTransferMessage(msg message.Receive) (
 		return
 	}
 
+	jww.DEBUG.Printf("[FT] Received new file transfer %s from %s {name: %q, "+
+		"type: %q, size: %d, parts: %d, numFps: %d, retry: %f}", tid, msg.Sender,
+		newFT.FileName, newFT.FileType, newFT.Size, numParts, numFps, newFT.Retry)
+
 	return tid, newFT.FileName, newFT.FileType, msg.Sender, newFT.Size,
 		newFT.Preview, nil
 }
diff --git a/fileTransfer/send.go b/fileTransfer/send.go
index b92133a4ca870a59cc7df42600f227cf1fedf679..24d7f0064bfbb44f0c83559a406ef57817388be8 100644
--- a/fileTransfer/send.go
+++ b/fileTransfer/send.go
@@ -392,14 +392,14 @@ func (m *Manager) makeRoundEventCallback(
 				// If the round succeeded, then set all parts for each transfer
 				// for this round to finished and call the progress callback
 				for _, tid := range sentRounds[rid] {
-					transfer, err := m.sent.GetTransfer(tid)
+					st, err := m.sent.GetTransfer(tid)
 					if err != nil {
 						jww.ERROR.Printf(finishPassNoTransferErr, rid, tid, err)
 						continue
 					}
 
 					// Mark as finished
-					completed, err := transfer.FinishTransfer(rid)
+					completed, err := st.FinishTransfer(rid)
 					if err != nil {
 						jww.ERROR.Printf(finishTransferErr, tid, err)
 						continue
@@ -408,17 +408,23 @@ func (m *Manager) makeRoundEventCallback(
 					// If the transfer is complete, send an E2E message to the
 					// recipient informing them
 					if completed {
+						jww.DEBUG.Printf("[FT] Finished sending file "+
+							"transfer %s to %s {parts: %d, numFps: %d/%d}",
+							tid, st.GetRecipient(), st.GetNumParts(),
+							st.GetNumFps()-st.GetNumAvailableFps(),
+							st.GetNumFps())
+
 						go func(tid ftCrypto.TransferID, recipient *id.ID) {
 							err = m.sendEndE2eMessage(recipient)
 							if err != nil {
 								jww.ERROR.Printf(finishedEndE2eMsfErr,
 									recipient, tid, err)
 							}
-						}(tid, transfer.GetRecipient())
+						}(tid, st.GetRecipient())
 					}
 
 					// Call progress callback after change in progress
-					transfer.CallProgressCB(nil)
+					st.CallProgressCB(nil)
 				}
 			} else {
 
@@ -428,20 +434,20 @@ func (m *Manager) makeRoundEventCallback(
 				// for this round from the in-progress list, call the progress
 				// callback with an error, and add the parts back into the queue
 				for _, tid := range sentRounds[rid] {
-					transfer, err := m.sent.GetTransfer(tid)
+					st, err := m.sent.GetTransfer(tid)
 					if err != nil {
 						jww.ERROR.Printf(finishFailNoTransferErr, rid, tid, err)
 						continue
 					}
 
 					// Remove parts from in-progress list
-					partsToResend, err := transfer.UnsetInProgress(rid)
+					partsToResend, err := st.UnsetInProgress(rid)
 					if err != nil {
 						jww.ERROR.Printf(unsetInProgressErr, tid, roundResult)
 					}
 
 					// Call progress callback after change in progress
-					transfer.CallProgressCB(nil)
+					st.CallProgressCB(nil)
 
 					// Add all the unsent parts back in the queue
 					m.queueParts(tid, partsToResend)
diff --git a/storage/fileTransfer/receiveFileTransfers.go b/storage/fileTransfer/receiveFileTransfers.go
index 7c624e434d7dedc00706fb17c81137080f8dcc46..ac9f262e6b2f6920fad1cf17a0453e3f89ace8c2 100644
--- a/storage/fileTransfer/receiveFileTransfers.go
+++ b/storage/fileTransfer/receiveFileTransfers.go
@@ -174,36 +174,40 @@ func (rft *ReceivedFileTransfersStore) DeleteTransfer(tid ftCrypto.TransferID) e
 // number and transfer ID are looked up using the fingerprint. Then the part is
 // added to the transfer with the corresponding transfer ID. Returns the
 // transfer that the part was added to so that a progress callback can be
-// called. Returns the transfer ID so that it can be used for logging.
+// called. Returns the transfer ID so that it can be used for logging. Also
+// returns of the transfer is complete after adding the part.
 func (rft *ReceivedFileTransfersStore) AddPart(encryptedPart, padding,
 	mac []byte, partNum uint16, fp format.Fingerprint) (*ReceivedTransfer,
-	ftCrypto.TransferID, error) {
+	ftCrypto.TransferID, bool, error) {
 	rft.mux.Lock()
 	defer rft.mux.Unlock()
 
 	// Lookup the part info for the given fingerprint
 	info, exists := rft.info[fp]
 	if !exists {
-		return nil, ftCrypto.TransferID{}, errors.Errorf(noFingerprintErr, fp)
+		return nil, ftCrypto.TransferID{}, false,
+			errors.Errorf(noFingerprintErr, fp)
 	}
 
 	// Lookup the transfer with the ID in the part info
 	transfer, exists := rft.transfers[info.id]
 	if !exists {
-		return nil, info.id, errors.Errorf(getReceivedTransferErr, info.id)
+		return nil, info.id, false,
+			errors.Errorf(getReceivedTransferErr, info.id)
 	}
 
 	// Add the part to the transfer
-	err := transfer.AddPart(encryptedPart, padding, mac, partNum, info.fpNum)
+	completed, err := transfer.AddPart(
+		encryptedPart, padding, mac, partNum, info.fpNum)
 	if err != nil {
-		return transfer, info.id, errors.Errorf(
+		return transfer, info.id, false, errors.Errorf(
 			addPartErr, partNum, transfer.numParts, info.id, err)
 	}
 
 	// Remove the part info from the map
 	delete(rft.info, fp)
 
-	return transfer, info.id, nil
+	return transfer, info.id, completed, nil
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/storage/fileTransfer/receiveFileTransfers_test.go b/storage/fileTransfer/receiveFileTransfers_test.go
index 08571865ed434ba26f3fcfebf1549dbcc5947d42..0c048246023069538f20870b89a8a2dbb60d1d47 100644
--- a/storage/fileTransfer/receiveFileTransfers_test.go
+++ b/storage/fileTransfer/receiveFileTransfers_test.go
@@ -352,7 +352,7 @@ func TestReceivedFileTransfersStore_AddPart(t *testing.T) {
 	fp := ftCrypto.GenerateFingerprint(key, fpNum)
 
 	// Add encrypted part
-	rt, _, err := rft.AddPart(encryptedPart, padding, mac, partNum, fp)
+	rt, _, _, err := rft.AddPart(encryptedPart, padding, mac, partNum, fp)
 	if err != nil {
 		t.Errorf("AddPart returned an error: %+v", err)
 	}
@@ -393,7 +393,7 @@ func TestReceivedFileTransfersStore_AddPart_NoFingerprintError(t *testing.T) {
 
 	// Add encrypted part
 	expectedErr := fmt.Sprintf(noFingerprintErr, fp)
-	_, _, err = rft.AddPart([]byte{}, []byte{}, []byte{}, 0, fp)
+	_, _, _, err = rft.AddPart([]byte{}, []byte{}, []byte{}, 0, fp)
 	if err == nil || err.Error() != expectedErr {
 		t.Errorf("AddPart did not return the expected error when no part for "+
 			"the fingerprint exists.\nexpected: %s\nreceived: %+v",
@@ -427,7 +427,7 @@ func TestReceivedFileTransfersStore_AddPart_NoTransferError(t *testing.T) {
 
 	// Add encrypted part
 	expectedErr := fmt.Sprintf(getReceivedTransferErr, invalidTid)
-	_, _, err = rft.AddPart([]byte{}, []byte{}, []byte{}, 0, fp)
+	_, _, _, err = rft.AddPart([]byte{}, []byte{}, []byte{}, 0, fp)
 	if err == nil || err.Error() != expectedErr {
 		t.Errorf("AddPart did not return the expected error when no transfer "+
 			"for the ID exists.\nexpected: %s\nreceived: %+v", expectedErr, err)
@@ -462,7 +462,7 @@ func TestReceivedFileTransfersStore_AddPart_AddPartError(t *testing.T) {
 
 	// Add encrypted part
 	expectedErr := fmt.Sprintf(addPartErr, partNum, numParts, tid, "")
-	_, _, err = rft.AddPart(encryptedPart, padding, mac, partNum, fp)
+	_, _, _, err = rft.AddPart(encryptedPart, padding, mac, partNum, fp)
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
 		t.Errorf("AddPart did not return the expected error when the "+
 			"encrypted part, padding, and MAC are invalid."+
diff --git a/storage/fileTransfer/receiveTransfer.go b/storage/fileTransfer/receiveTransfer.go
index 3a29e5271e24e12da9e49047b6340e5bc38ba66a..1f5d0756c33fe1fe66931ed7789886a865ca2c23 100644
--- a/storage/fileTransfer/receiveTransfer.go
+++ b/storage/fileTransfer/receiveTransfer.go
@@ -274,9 +274,10 @@ func (rt *ReceivedTransfer) AddProgressCB(
 }
 
 // AddPart decrypts an encrypted file part, adds it to the list of received
-// parts and marks its fingerprint as used.
+// parts and marks its fingerprint as used. Returns true if the part added was
+// the last in the transfer.
 func (rt *ReceivedTransfer) AddPart(encryptedPart, padding, mac []byte, partNum,
-	fpNum uint16) error {
+	fpNum uint16) (bool, error) {
 	rt.mux.Lock()
 	defer rt.mux.Unlock()
 
@@ -284,13 +285,13 @@ func (rt *ReceivedTransfer) AddPart(encryptedPart, padding, mac []byte, partNum,
 	decryptedPart, err := ftCrypto.DecryptPart(
 		rt.key, encryptedPart, padding, mac, fpNum)
 	if err != nil {
-		return err
+		return false, err
 	}
 
 	// Add the part to the list of parts
 	err = rt.receivedParts.addPart(decryptedPart, partNum)
 	if err != nil {
-		return err
+		return false, err
 	}
 
 	// Mark the fingerprint as used
@@ -299,7 +300,11 @@ func (rt *ReceivedTransfer) AddPart(encryptedPart, padding, mac []byte, partNum,
 	// Mark part as received
 	rt.receivedStatus.Use(uint32(partNum))
 
-	return nil
+	if rt.receivedStatus.GetNumUsed() >= uint32(rt.numParts) {
+		return true, nil
+	}
+
+	return false, nil
 }
 
 // GetFile returns all the file parts combined into a single byte slice. An
diff --git a/storage/fileTransfer/receiveTransfer_test.go b/storage/fileTransfer/receiveTransfer_test.go
index 728480c63756ce39bf681819eaa4ad5f24013f45..7c0382ec2f038899e9f1d047b087e958e0795abc 100644
--- a/storage/fileTransfer/receiveTransfer_test.go
+++ b/storage/fileTransfer/receiveTransfer_test.go
@@ -544,11 +544,15 @@ func TestReceivedTransfer_AddPart(t *testing.T) {
 		rt.key, expectedData, fpNum, t)
 
 	// Add encrypted part
-	err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
+	complete, err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
 	if err != nil {
 		t.Errorf("AddPart returned an error: %+v", err)
 	}
 
+	if complete {
+		t.Errorf("Transfer complete when it should not be.")
+	}
+
 	receivedData, exists := rt.receivedParts.parts[partNum]
 	if !exists {
 		t.Errorf("Part #%d not found in part map.", partNum)
@@ -597,7 +601,7 @@ func TestReceivedTransfer_AddPart_DecryptPartError(t *testing.T) {
 
 	// Add encrypted part
 	expectedErr := "reconstructed MAC from decrypting does not match MAC from sender"
-	err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
+	_, err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
 	if err == nil || err.Error() != expectedErr {
 		t.Errorf("AddPart did not return the expected error when the MAC is "+
 			"invalid.\nexpected: %s\nreceived: %+v", expectedErr, err)
@@ -670,7 +674,7 @@ func Test_loadReceivedTransfer(t *testing.T) {
 		expectedRT.key, expectedData, fpNum, t)
 
 	// Add encrypted part
-	err := expectedRT.AddPart(encryptedPart, padding, mac, partNum, fpNum)
+	_, err := expectedRT.AddPart(encryptedPart, padding, mac, partNum, fpNum)
 	if err != nil {
 		t.Errorf("Failed to add test part: %+v", err)
 	}
@@ -713,7 +717,7 @@ func Test_loadReceivedTransfer_LoadFpVectorError(t *testing.T) {
 	encryptedPart, mac, padding := newEncryptedPartData(rt.key, data, fpNum, t)
 
 	// Add encrypted part
-	err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
+	_, err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
 	if err != nil {
 		t.Errorf("Failed to add test part: %+v", err)
 	}
@@ -745,7 +749,7 @@ func Test_loadReceivedTransfer_LoadPartStoreError(t *testing.T) {
 	encryptedPart, mac, padding := newEncryptedPartData(rt.key, data, fpNum, t)
 
 	// Add encrypted part
-	err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
+	_, err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
 	if err != nil {
 		t.Errorf("Failed to add test part: %+v", err)
 	}
@@ -777,7 +781,7 @@ func Test_loadReceivedTransfer_LoadReceivedVectorError(t *testing.T) {
 	encryptedPart, mac, padding := newEncryptedPartData(rt.key, data, fpNum, t)
 
 	// Add encrypted part
-	err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
+	_, err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
 	if err != nil {
 		t.Errorf("Failed to add test part: %+v", err)
 	}
@@ -871,7 +875,7 @@ func TestReceivedTransfer_delete(t *testing.T) {
 		rt.key, expectedData, fpNum, t)
 
 	// Add encrypted part
-	err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
+	_, err := rt.AddPart(encryptedPart, padding, mac, partNum, fpNum)
 	if err != nil {
 		t.Fatalf("Failed to add test part: %+v", err)
 	}
@@ -1027,7 +1031,7 @@ func newRandomReceivedTransfer(numParts, numFps uint16, kv *versioned.KV,
 
 	for partNum, part := range parts.parts {
 		encryptedPart, mac, padding := newEncryptedPartData(key, part, partNum, t)
-		err := rt.AddPart(encryptedPart, padding, mac, partNum, partNum)
+		_, err := rt.AddPart(encryptedPart, padding, mac, partNum, partNum)
 		if err != nil {
 			t.Errorf("Failed to add part #%d: %+v", partNum, err)
 		}