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
- Remove leading/trailing slashes: use `appDir: '_app'` (the default).
- If you intended to change where assets are served from, configure `paths.base`/`paths.relative` instead of appDir.
- 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
- Leave appDir at its default '_app' unless you have a concrete reason
- Use paths.base/paths.relative for URL prefixing needs, not appDir
- Never copy URL paths (with slashes) into appDir
- Validate config with the official schema before builds
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
- Invalid isr.expiration value: ${JSON.stringify(value)} (${de
- The SvelteKit options from the Vite config must be an object
- ${keypath} should be "fail", "warn", "ignore" or a custom fu
- The SvelteKit Vite plugin ${keypath} should be an object wit
- ${keypath} should be an object
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/45c8423c4b07e271.
Report an issue: GitHub.