sveltejs/kit · error · Error

${keypath} cannot start or end with '/'. See https://svelte.

Error message

${keypath} cannot start or end with '/'. See https://svelte.dev/docs/kit/configuration

What it means

`kit.appDir` is the directory name under the build output where SvelteKit places immutable app assets, and it becomes part of URLs. It must be a non-empty relative path segment, so validate throws when it starts or ends with '/' (an empty string throws the sibling 'cannot be empty' error).

Source

Thrown at packages/kit/src/core/config/options.js:76

				throw new Error(`${keypath} should be an object`);
			}

			for (const key in input) {
				assert_string(input[key], `${keypath}.${key}`);
			}

			return input;
		}),
		(keypath) =>
			`The \`${keypath}\` option is deprecated, and will be removed in a future version of SvelteKit. Use subpath imports instead: https://svelte.dev/docs/kit/$lib`
	),

	appDir: validate('_app', (input, keypath) => {
		assert_string(input, keypath);

		if (input) {
			if (input.startsWith('/') || input.endsWith('/')) {
				throw new Error(
					`${keypath} cannot start or end with '/'. See https://svelte.dev/docs/kit/configuration`
				);
			}
		} else {
			throw new Error(`${keypath} cannot be empty`);
		}

		return input;
	}),

	compilerOptions: any(),

	csp: object({
		mode: list(['auto', 'hash', 'nonce']),
		directives,
		reportOnly: directives
	}),

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Remove leading/trailing slashes: use `appDir: '_app'` (the default).
  2. If you intended to change where assets are served from, configure `paths.base`/`paths.relative` instead of appDir.
  3. Keep appDir as a single relative segment without slashes on either end.

Example fix

// before
kit: { appDir: '/_app/' }
// after
kit: { appDir: '_app' }
Defensive patterns

Strategy: validation

Validate before calling

const appDir = config.kit?.appDir;
if (typeof appDir === 'string' && (appDir.startsWith('/') || appDir.endsWith('/') || appDir === '')) {
  throw new Error('kit.appDir must be a relative segment without leading/trailing slashes');
}

Type guard

/** @returns {boolean} */
function isValidAppDir(v) {
  return typeof v === 'string' && v.length > 0 && !v.startsWith('/') && !v.endsWith('/');
}

Try / catch

try {
  await viteBuild();
} catch (e) {
  if (e.message.includes("cannot start or end with '/'")) {
    console.error('kit.appDir is relative — strip leading/trailing slashes');
  }
  throw e;
}

Prevention

When it happens

Trigger: validate_options validates config.kit.appDir; assert_string passes (it is a string) but `input.startsWith('/') || input.endsWith('/')` is true, e.g. '/_app' or '_app/'.

Common situations: Users add a leading slash assuming URL-path semantics; copying an absolute path from a CDN/base-path config; trailing slash left from a copy-paste of a URL.

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/45c8423c4b07e271. Report an issue: GitHub.