diff --git a/.changeset/bright-gifts-prove.md b/.changeset/bright-gifts-prove.md
new file mode 100644
index 0000000000..14b1a3bde1
--- /dev/null
+++ b/.changeset/bright-gifts-prove.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+Updates a reference in an error message
diff --git a/.changeset/unlucky-wasps-refuse.md b/.changeset/unlucky-wasps-refuse.md
new file mode 100644
index 0000000000..5e0d4d664b
--- /dev/null
+++ b/.changeset/unlucky-wasps-refuse.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/markdown-remark': patch
+---
+
+Fixes frontmatter parsing if file is encoded in UTF8 with BOM
diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts
index a737843299..0c54a16c7b 100644
--- a/packages/astro/src/core/app/index.ts
+++ b/packages/astro/src/core/app/index.ts
@@ -260,7 +260,6 @@ export class App {
 				this.#logger.error(null, error.stack!);
 				return this.#renderError(request, { status: 500, error, clientAddress });
 			}
-			Reflect.set(request, clientLocalsSymbol, locals);
 		}
 		if (!routeData) {
 			routeData = this.match(request);
diff --git a/packages/astro/src/core/base-pipeline.ts b/packages/astro/src/core/base-pipeline.ts
index 545cf5ed28..81cc553ba7 100644
--- a/packages/astro/src/core/base-pipeline.ts
+++ b/packages/astro/src/core/base-pipeline.ts
@@ -1,4 +1,3 @@
-import { setGetEnv } from '../env/runtime.js';
 import { createI18nMiddleware } from '../i18n/middleware.js';
 import type { ComponentInstance } from '../types/astro.js';
 import type { MiddlewareHandler, RewritePayload } from '../types/public/common.js';
@@ -10,8 +9,6 @@ import type {
 	SSRResult,
 } from '../types/public/internal.js';
 import { createOriginCheckMiddleware } from './app/middlewares.js';
-import { AstroError } from './errors/errors.js';
-import { AstroErrorData } from './errors/index.js';
 import type { Logger } from './logger/core.js';
 import { NOOP_MIDDLEWARE_FN } from './middleware/noop-middleware.js';
 import { sequence } from './middleware/sequence.js';
diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts
index 6b867d7c46..646766ae06 100644
--- a/packages/astro/src/core/errors/errors-data.ts
+++ b/packages/astro/src/core/errors/errors-data.ts
@@ -985,7 +985,7 @@ export const AstroGlobNoMatch = {
 /**
  * @docs
  * @see
- * - [Astro.redirect](https://docs.astro.build/en/reference/api-reference/#astroredirect)
+ * - [Astro.redirect](https://docs.astro.build/en/reference/api-reference/#redirect)
  * @description
  * A redirect must be given a location with the `Location` header.
  */
diff --git a/packages/astro/src/core/middleware/index.ts b/packages/astro/src/core/middleware/index.ts
index c7ed6e6479..7f4c2867ed 100644
--- a/packages/astro/src/core/middleware/index.ts
+++ b/packages/astro/src/core/middleware/index.ts
@@ -39,6 +39,11 @@ export type CreateContext = {
 	 * User defined default locale
 	 */
 	defaultLocale: string;
+
+	/**
+	 * Initial value of the locals
+	 */
+	locals: App.Locals;
 };
 
 /**
@@ -49,6 +54,7 @@ function createContext({
 	params = {},
 	userDefinedLocales = [],
 	defaultLocale = '',
+	locals,
 }: CreateContext): APIContext {
 	let preferredLocale: string | undefined = undefined;
 	let preferredLocaleList: string[] | undefined = undefined;
@@ -104,15 +110,15 @@ function createContext({
 			return clientIpAddress;
 		},
 		get locals() {
-			let locals = Reflect.get(request, clientLocalsSymbol);
+			// TODO: deprecate this usage. This is used only by the edge middleware for now, so its usage should be basically none.
+			let _locals = locals ?? Reflect.get(request, clientLocalsSymbol);
 			if (locals === undefined) {
-				locals = {};
-				Reflect.set(request, clientLocalsSymbol, locals);
+				_locals = {};
 			}
-			if (typeof locals !== 'object') {
+			if (typeof _locals !== 'object') {
 				throw new AstroError(AstroErrorData.LocalsNotAnObject);
 			}
-			return locals;
+			return _locals;
 		},
 		set locals(_) {
 			throw new AstroError(AstroErrorData.LocalsReassigned);
diff --git a/packages/astro/src/core/request.ts b/packages/astro/src/core/request.ts
index b8cc89fb84..302370ba8d 100644
--- a/packages/astro/src/core/request.ts
+++ b/packages/astro/src/core/request.ts
@@ -24,8 +24,6 @@ export interface CreateRequestOptions {
 	routePattern: string;
 }
 
-const clientLocalsSymbol = Symbol.for('astro.locals');
-
 /**
  * Used by astro internals to create a web standard request object.
  *
@@ -39,7 +37,6 @@ export function createRequest({
 	method = 'GET',
 	body = undefined,
 	logger,
-	locals,
 	isPrerendered = false,
 	routePattern,
 }: CreateRequestOptions): Request {
@@ -93,7 +90,5 @@ export function createRequest({
 		});
 	}
 
-	Reflect.set(request, clientLocalsSymbol, locals ?? {});
-
 	return request;
 }
diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts
index fbdc79db07..7ab12c43df 100644
--- a/packages/astro/src/vite-plugin-astro-server/route.ts
+++ b/packages/astro/src/vite-plugin-astro-server/route.ts
@@ -161,6 +161,7 @@ export async function handleRoute({
 	let mod: ComponentInstance | undefined = undefined;
 	let route: RouteData;
 	const middleware = (await loadMiddleware(loader)).onRequest;
+	// This is required for adapters to set locals in dev mode. They use a dev server middleware to inject locals to the `http.IncomingRequest` object.
 	const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
 
 	const { preloadedComponent } = matchedRoute;
@@ -245,7 +246,7 @@ export async function handleRoute({
 		const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline);
 		if (fourOhFourRoute) {
 			renderContext = await RenderContext.create({
-				locals,
+				locals: {},
 				pipeline,
 				pathname,
 				middleware: isDefaultPrerendered404(fourOhFourRoute.route) ? undefined : middleware,
diff --git a/packages/astro/test/units/routing/api-context.test.js b/packages/astro/test/units/routing/api-context.test.js
index 1e955e50cc..027a70f8bf 100644
--- a/packages/astro/test/units/routing/api-context.test.js
+++ b/packages/astro/test/units/routing/api-context.test.js
@@ -16,4 +16,21 @@ describe('createAPIContext', () => {
 
 		assert.equal(context.clientAddress, '192.0.2.43');
 	});
+
+	it('should return the correct locals', () => {
+		const request = new Request('http://example.com', {
+			headers: {
+				'x-forwarded-for': '192.0.2.43, 172.16.58.3',
+			},
+		});
+
+		const context = createContext({
+			request,
+			locals: {
+				foo: 'bar',
+			},
+		});
+
+		assert.deepEqual(context.locals, { foo: 'bar' });
+	});
 });
diff --git a/packages/astro/test/units/vite-plugin-astro-server/response.test.js b/packages/astro/test/units/vite-plugin-astro-server/response.test.js
index 2d256fb71a..912ef4102f 100644
--- a/packages/astro/test/units/vite-plugin-astro-server/response.test.js
+++ b/packages/astro/test/units/vite-plugin-astro-server/response.test.js
@@ -87,16 +87,17 @@ describe('endpoints', () => {
 			url: '/streaming',
 		});
 
-		const locals = { cancelledByTheServer: false };
-		req[Symbol.for('astro.locals')] = locals;
-
 		container.handle(req, res);
 
 		await new Promise((resolve) => setTimeout(resolve, 500));
 		res.emit('close');
 
-		await done;
+		try {
+			await done;
 
-		assert.equal(locals.cancelledByTheServer, true);
+			assert.ok(true);
+		} catch (err) {
+			assert.fail(err);
+		}
 	});
 });
diff --git a/packages/markdown/remark/src/frontmatter.ts b/packages/markdown/remark/src/frontmatter.ts
index 94fbec2b33..fe878df662 100644
--- a/packages/markdown/remark/src/frontmatter.ts
+++ b/packages/markdown/remark/src/frontmatter.ts
@@ -11,9 +11,10 @@ export function isFrontmatterValid(frontmatter: Record<string, any>) {
 }
 
 // Capture frontmatter wrapped with `---`, including any characters and new lines within it.
-// Only capture if it exists near the top of the file (whitespaces between the start of file and
-// the start of `---` are allowed)
-const frontmatterRE = /^\s*---([\s\S]*?\n)---/;
+// Only capture if `---` exists near the top of the file, including:
+// 1. Start of file (including if has BOM encoding)
+// 2. Start of file with any whitespace (but `---` must still start on a new line)
+const frontmatterRE = /(?:^\uFEFF?|^\s*\n)---([\s\S]*?\n)---/;
 export function extractFrontmatter(code: string): string | undefined {
 	return frontmatterRE.exec(code)?.[1];
 }
diff --git a/packages/markdown/remark/test/frontmatter.test.js b/packages/markdown/remark/test/frontmatter.test.js
index 6a8b6b37ca..155368e59f 100644
--- a/packages/markdown/remark/test/frontmatter.test.js
+++ b/packages/markdown/remark/test/frontmatter.test.js
@@ -2,16 +2,21 @@ import assert from 'node:assert/strict';
 import { describe, it } from 'node:test';
 import { extractFrontmatter, parseFrontmatter } from '../dist/index.js';
 
+const bom = '\uFEFF';
+
 describe('extractFrontmatter', () => {
 	it('works', () => {
 		const yaml = `\nfoo: bar\n`;
 		assert.equal(extractFrontmatter(`---${yaml}---`), yaml);
-		assert.equal(extractFrontmatter(`  ---${yaml}---`), yaml);
+		assert.equal(extractFrontmatter(`${bom}---${yaml}---`), yaml);
 		assert.equal(extractFrontmatter(`\n---${yaml}---`), yaml);
 		assert.equal(extractFrontmatter(`\n  \n---${yaml}---`), yaml);
 		assert.equal(extractFrontmatter(`---${yaml}---\ncontent`), yaml);
+		assert.equal(extractFrontmatter(`${bom}---${yaml}---\ncontent`), yaml);
 		assert.equal(extractFrontmatter(`\n\n---${yaml}---\n\ncontent`), yaml);
 		assert.equal(extractFrontmatter(`\n  \n---${yaml}---\n\ncontent`), yaml);
+		assert.equal(extractFrontmatter(` ---${yaml}---`), undefined);
+		assert.equal(extractFrontmatter(`---${yaml} ---`), undefined);
 		assert.equal(extractFrontmatter(`text\n---${yaml}---\n\ncontent`), undefined);
 	});
 });
@@ -24,10 +29,10 @@ describe('parseFrontmatter', () => {
 			rawFrontmatter: yaml,
 			content: '',
 		});
-		assert.deepEqual(parseFrontmatter(`  ---${yaml}---`), {
+		assert.deepEqual(parseFrontmatter(`${bom}---${yaml}---`), {
 			frontmatter: { foo: 'bar' },
 			rawFrontmatter: yaml,
-			content: '  ',
+			content: bom,
 		});
 		assert.deepEqual(parseFrontmatter(`\n---${yaml}---`), {
 			frontmatter: { foo: 'bar' },
@@ -44,6 +49,11 @@ describe('parseFrontmatter', () => {
 			rawFrontmatter: yaml,
 			content: '\ncontent',
 		});
+		assert.deepEqual(parseFrontmatter(`${bom}---${yaml}---\ncontent`), {
+			frontmatter: { foo: 'bar' },
+			rawFrontmatter: yaml,
+			content: `${bom}\ncontent`,
+		});
 		assert.deepEqual(parseFrontmatter(`\n\n---${yaml}---\n\ncontent`), {
 			frontmatter: { foo: 'bar' },
 			rawFrontmatter: yaml,
@@ -54,6 +64,16 @@ describe('parseFrontmatter', () => {
 			rawFrontmatter: yaml,
 			content: '\n  \n\n\ncontent',
 		});
+		assert.deepEqual(parseFrontmatter(` ---${yaml}---`), {
+			frontmatter: {},
+			rawFrontmatter: '',
+			content: ` ---${yaml}---`,
+		});
+		assert.deepEqual(parseFrontmatter(`---${yaml} ---`), {
+			frontmatter: {},
+			rawFrontmatter: '',
+			content: `---${yaml} ---`,
+		});
 		assert.deepEqual(parseFrontmatter(`text\n---${yaml}---\n\ncontent`), {
 			frontmatter: {},
 			rawFrontmatter: '',