diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/UnsupportedVersionException.java b/bramble-api/src/main/java/org/briarproject/bramble/api/UnsupportedVersionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7cf2985641e6b55092b551213a9f2f7cff62617
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/UnsupportedVersionException.java
@@ -0,0 +1,9 @@
+package org.briarproject.bramble.api;
+
+import java.io.IOException;
+
+/**
+ * An exception that indicates an unrecoverable version mismatch.
+ */
+public class UnsupportedVersionException extends IOException {
+}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/PayloadParserImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/PayloadParserImpl.java
index ecf519e09e5c9827a9dcc8a4c5be24ad895c68b2..334a46f3156b78651c926d4bd0f8c67d207ec588 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/PayloadParserImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/PayloadParserImpl.java
@@ -1,6 +1,7 @@
 package org.briarproject.bramble.keyagreement;
 
 import org.briarproject.bramble.api.FormatException;
+import org.briarproject.bramble.api.UnsupportedVersionException;
 import org.briarproject.bramble.api.data.BdfList;
 import org.briarproject.bramble.api.data.BdfReader;
 import org.briarproject.bramble.api.data.BdfReaderFactory;
@@ -46,7 +47,9 @@ class PayloadParserImpl implements PayloadParser {
 		if (!r.eof()) throw new FormatException();
 		// First element: the protocol version
 		long protocolVersion = payload.getLong(0);
-		if (protocolVersion != PROTOCOL_VERSION) throw new FormatException();
+		if (protocolVersion != PROTOCOL_VERSION) {
+			throw new UnsupportedVersionException();
+		}
 		// Second element: the public key commitment
 		byte[] commitment = payload.getRaw(1);
 		if (commitment.length != COMMIT_LENGTH) throw new FormatException();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/BaseFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/BaseFragment.java
index 0fa3ee7b6d2fbbc7c113338df30c8e7303306868..f45d7c54f68aa940edb8535ee200f3c1e143c060 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/BaseFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/BaseFragment.java
@@ -30,7 +30,7 @@ public abstract class BaseFragment extends Fragment
 	}
 
 	@Override
-	public void onCreate(Bundle savedInstanceState) {
+	public void onCreate(@Nullable Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 
 		// allow for "up" button to act as back button
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ErrorFragment.java
new file mode 100644
index 0000000000000000000000000000000000000000..81654e0aa754cdca4ffe4eb2d5f57a61d9d81231
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ErrorFragment.java
@@ -0,0 +1,65 @@
+package org.briarproject.briar.android.fragment;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.activity.ActivityComponent;
+
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class ErrorFragment extends BaseFragment {
+
+	private static final String TAG = ErrorFragment.class.getSimpleName();
+
+	private static final String ERROR_MSG = "errorMessage";
+
+	public static ErrorFragment newInstance(String message) {
+		ErrorFragment f = new ErrorFragment();
+		Bundle args = new Bundle();
+		args.putString(ERROR_MSG, message);
+		f.setArguments(args);
+		return f;
+	}
+
+	private String errorMessage;
+
+	@Override
+	public String getUniqueTag() {
+		return TAG;
+	}
+
+	@Override
+	public void onCreate(@Nullable Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+
+		Bundle args = getArguments();
+		if (args == null) throw new AssertionError();
+		errorMessage = args.getString(ERROR_MSG);
+	}
+
+	@Nullable
+	@Override
+	public View onCreateView(LayoutInflater inflater,
+			@Nullable ViewGroup container,
+			@Nullable Bundle savedInstanceState) {
+		View v = inflater
+				.inflate(R.layout.fragment_error, container, false);
+		TextView msg = v.findViewById(R.id.errorMessage);
+		msg.setText(errorMessage);
+		return v;
+	}
+
+	@Override
+	public void injectFragment(ActivityComponent component) {
+		// not necessary
+	}
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
index 1ef7dcd2302956920d6f81f6cc6ce1b98d4af319..5649354bdcc3b5f7ddb9a6c59e2a1e3d71dcb411 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
@@ -17,6 +17,7 @@ import android.widget.Toast;
 
 import com.google.zxing.Result;
 
+import org.briarproject.bramble.api.UnsupportedVersionException;
 import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
@@ -35,6 +36,7 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
 import org.briarproject.briar.R;
 import org.briarproject.briar.android.activity.ActivityComponent;
 import org.briarproject.briar.android.fragment.BaseEventFragment;
+import org.briarproject.briar.android.fragment.ErrorFragment;
 
 import java.io.IOException;
 import java.util.concurrent.Executor;
@@ -200,8 +202,14 @@ public class ShowQrCodeFragment extends BaseEventFragment
 			statusView.setVisibility(VISIBLE);
 			status.setText(R.string.connecting_to_device);
 			task.connectAndRunProtocol(remotePayload);
+		} catch (UnsupportedVersionException e) {
+			reset();
+			String msg = getString(R.string.qr_code_unsupported,
+					getString(R.string.app_name));
+			showNextFragment(ErrorFragment.newInstance(msg));
 		} catch (IOException | IllegalArgumentException e) {
-			// TODO show failure
+			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, "QR Code Invalid", e);
+			reset();
 			Toast.makeText(getActivity(), R.string.qr_code_invalid,
 					LENGTH_LONG).show();
 		}
diff --git a/briar-android/src/main/res/drawable/alerts_and_states_error.xml b/briar-android/src/main/res/drawable/alerts_and_states_error.xml
index b84f896b671ff0b86f86635464621103e3ff0f78..02056c85cec5acdaae01308058a264b1c07b4a3f 100644
--- a/briar-android/src/main/res/drawable/alerts_and_states_error.xml
+++ b/briar-android/src/main/res/drawable/alerts_and_states_error.xml
@@ -1,5 +1,9 @@
-<vector android:alpha="0.54" android:height="24dp"
-    android:viewportHeight="24.0" android:viewportWidth="24.0"
-    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="#FF000000" android:pathData="M15.73,3L8.27,3L3,8.27v7.46L8.27,21h7.46L21,15.73L21,8.27L15.73,3zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3 0.72,0 1.3,0.58 1.3,1.3 0,0.72 -0.58,1.3 -1.3,1.3zM13,13h-2L11,7h2v6z"/>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="128dp"
+        android:height="128dp"
+        android:viewportHeight="24.0"
+        android:viewportWidth="24.0">
+	<path
+		android:fillColor="#FF000000"
+		android:pathData="M15.73,3L8.27,3L3,8.27v7.46L8.27,21h7.46L21,15.73L21,8.27L15.73,3zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3 0.72,0 1.3,0.58 1.3,1.3 0,0.72 -0.58,1.3 -1.3,1.3zM13,13h-2L11,7h2v6z"/>
 </vector>
diff --git a/briar-android/src/main/res/layout/fragment_error.xml b/briar-android/src/main/res/layout/fragment_error.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4870bf8ee47b99070d9d9a3129b8ba7d64061b7b
--- /dev/null
+++ b/briar-android/src/main/res/layout/fragment_error.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:app="http://schemas.android.com/apk/res-auto"
+	xmlns:tools="http://schemas.android.com/tools"
+	android:layout_width="match_parent"
+	android:layout_height="match_parent">
+
+	<ImageView
+		android:id="@+id/errorIcon"
+		android:layout_width="128dp"
+		android:layout_height="128dp"
+		android:layout_marginEnd="8dp"
+		android:layout_marginStart="8dp"
+		android:layout_marginTop="8dp"
+		android:src="@drawable/alerts_and_states_error"
+		android:tint="?colorControlNormal"
+		app:layout_constraintEnd_toEndOf="parent"
+		app:layout_constraintStart_toStartOf="parent"
+		app:layout_constraintTop_toTopOf="parent"
+		tools:ignore="ContentDescription"/>
+
+	<TextView
+		android:id="@+id/errorTitle"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_marginEnd="8dp"
+		android:layout_marginStart="8dp"
+		android:layout_marginTop="8dp"
+		android:text="@string/sorry"
+		android:textSize="@dimen/text_size_xlarge"
+		app:layout_constraintEnd_toEndOf="parent"
+		app:layout_constraintStart_toStartOf="parent"
+		app:layout_constraintTop_toBottomOf="@+id/errorIcon"/>
+
+	<TextView
+		android:id="@+id/errorMessage"
+		android:layout_width="0dp"
+		android:layout_height="wrap_content"
+		android:layout_marginEnd="16dp"
+		android:layout_marginLeft="16dp"
+		android:layout_marginRight="16dp"
+		android:layout_marginStart="16dp"
+		android:layout_marginTop="8dp"
+		android:textSize="@dimen/text_size_medium"
+		app:layout_constraintEnd_toEndOf="parent"
+		app:layout_constraintStart_toStartOf="parent"
+		app:layout_constraintTop_toBottomOf="@+id/errorTitle"
+		tools:text="@string/qr_code_unsupported"/>
+
+</android.support.constraint.ConstraintLayout>
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index a990a022f21768f3e5a22956ac86c2c29f71d85e..90af1aaab47d427140ac6cd2115bd7e0cea0a03c 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -102,6 +102,7 @@
 	<string name="show_onboarding">Show Help Dialog</string>
 	<string name="fix">Fix</string>
 	<string name="help">Help</string>
+	<string name="sorry">Sorry</string>
 
 	<!-- Contacts and Private Conversations-->
 	<string name="no_contacts">It seems that you are new here and have no contacts yet.\n\nTap the + icon at the top and follow the instructions to add some friends to your list.\n\nPlease remember: You can only add new contacts face-to-face to prevent anyone from impersonating you or reading your messages in the future.</string>
@@ -125,6 +126,7 @@
 	<string name="contact_already_exists">Contact %s already exists</string>
 	<string name="contact_exchange_failed">Contact exchange failed</string>
 	<string name="qr_code_invalid">The QR code is invalid</string>
+	<string name="qr_code_unsupported">The QR code you are trying to scan belongs to an old version of %s which is no longer supported.\n\nPlease ensure that both of you are running the latest version and then try again.</string>
 	<string name="camera_error">Camera error</string>
 	<string name="connecting_to_device">Connecting to device\u2026</string>
 	<string name="authenticating_with_device">Authenticating with device\u2026</string>