diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0cc3e7f6f8..d73605ea77 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,22 @@
+#### v3.1.6 (2023-06-15)
+
+##### Chores
+
+*  incrementing version number - v3.1.5 (ec19343a)
+*  update changelog for v3.1.5 (b0d16861)
+*  incrementing version number - v3.1.4 (2452783c)
+*  incrementing version number - v3.1.3 (3b4e9d3f)
+*  incrementing version number - v3.1.2 (40fa3489)
+*  incrementing version number - v3.1.1 (40250733)
+*  incrementing version number - v3.1.0 (0cb386bd)
+*  incrementing version number - v3.0.1 (26f6ea49)
+*  incrementing version number - v3.0.0 (224e08cd)
+
+##### Bug Fixes
+
+*  #11717 prevent crash in messaging (8620a2cd)
+*  closes #11708, fix quick reply check (a757716d)
+
 #### v3.1.5 (2023-06-13)
 
 ##### Chores
diff --git a/src/controllers/accounts/follow.js b/src/controllers/accounts/follow.js
index b573418aad..44ad00d3de 100644
--- a/src/controllers/accounts/follow.js
+++ b/src/controllers/accounts/follow.js
@@ -15,7 +15,11 @@ followController.getFollowers = async function (req, res, next) {
 };
 
 async function getFollow(tpl, name, req, res) {
-	const { username, userslug, followerCount, followingCount } = await user.getUserFields(res.locals.uid, ['username', 'userslug']);
+	const {
+		username, userslug, followerCount, followingCount,
+	} = await user.getUserFields(res.locals.uid, [
+		'username', 'userslug', 'followerCount', 'followingCount',
+	]);
 
 	const page = parseInt(req.query.page, 10) || 1;
 	const resultsPerPage = 50;
diff --git a/src/controllers/composer.js b/src/controllers/composer.js
index d82214fb91..9475fbdba5 100644
--- a/src/controllers/composer.js
+++ b/src/controllers/composer.js
@@ -76,13 +76,20 @@ exports.post = async function (req, res) {
 		} else {
 			throw new Error('[[error:invalid-data]]');
 		}
+		if (!result) {
+			throw new Error('[[error:invalid-data]]');
+		}
 		if (result.queued) {
 			return res.redirect(`${nconf.get('relative_path') || '/'}?noScriptMessage=[[success:post-queued]]`);
 		}
-		const uid = result.uid ? result.uid : result.topicData.uid;
-		user.updateOnlineUsers(uid);
-		const path = result.pid ? `/post/${result.pid}` : `/topic/${result.topicData.slug}`;
-		res.redirect(nconf.get('relative_path') + path);
+		user.updateOnlineUsers(req.uid);
+		let path = nconf.get('relative_path');
+		if (result.pid) {
+			path += `/post/${result.pid}`;
+		} else if (result.topicData) {
+			path += `/topic/${result.topicData.slug}`;
+		}
+		res.redirect(path);
 	} catch (err) {
 		helpers.noScriptErrors(req, res, err.message, 400);
 	}
diff --git a/src/middleware/user.js b/src/middleware/user.js
index 6170c8cc00..c9713df9aa 100644
--- a/src/middleware/user.js
+++ b/src/middleware/user.js
@@ -239,7 +239,7 @@ module.exports = function (middleware) {
 		 */
 		const path = req.path.startsWith('/api/') ? req.path.replace('/api', '') : req.path;
 
-		if (req.uid && !(path.endsWith('/edit/email') || path.startsWith('/confirm/'))) {
+		if (req.uid > 0 && !(path.endsWith('/edit/email') || path.startsWith('/confirm/'))) {
 			const [confirmed, isAdmin] = await Promise.all([
 				user.getUserField(req.uid, 'email:confirmed'),
 				user.isAdministrator(req.uid),
diff --git a/test/controllers.js b/test/controllers.js
index 893d4892e8..aebd529266 100644
--- a/test/controllers.js
+++ b/test/controllers.js
@@ -2682,6 +2682,42 @@ describe('Controllers', () => {
 				});
 			});
 		});
+
+		it('should create a new topic and reply by composer route as a guest', async () => {
+			const jar = request.jar();
+			const csrf_token = await helpers.getCsrfToken(jar);
+			const data = {
+				cid: cid,
+				title: 'no js is good',
+				content: 'a topic with noscript',
+				handle: 'guest1',
+			};
+
+			await privileges.categories.give(['groups:topics:create', 'groups:topics:reply'], cid, 'guests');
+
+			const result = await helpers.request('post', `/compose`, {
+				form: data,
+				jar,
+				headers: {
+					'x-csrf-token': csrf_token,
+				},
+			});
+			assert.strictEqual(result.res.statusCode, 302);
+
+			const replyResult = await helpers.request('post', `/compose`, {
+				form: {
+					tid: tid,
+					content: 'a new reply',
+					handle: 'guest2',
+				},
+				jar,
+				headers: {
+					'x-csrf-token': csrf_token,
+				},
+			});
+			assert.equal(replyResult.res.statusCode, 302);
+			await privileges.categories.rescind(['groups:topics:post', 'groups:topics:reply'], cid, 'guests');
+		});
 	});
 
 	describe('test routes', () => {