sveltejs/kit · error · Error

should be a function, if specified

Error message

${keypath} should be a function, if specified

What it means

The `fun()` validator checks that an optional config option, when provided, is a function. If a non-function value is assigned to a hook or callback option (e.g. handle, handleError), SvelteKit throws this error at config load time.

Solutions

  1. Open svelte.config.js and locate the option named in the keypath.
  2. Ensure the value is a function reference, not a call result or string.
  3. Import the hook correctly: `handle: import('./hooks.server').then(m => m.handle)` is not allowed — use a direct function import or define it inline.

Example fix

// before
kit: { handle: './src/hooks.server.js' }
// after
import handle from './src/hooks.server.js';
const config = { kit: { handle } };
Defensive patterns

Strategy: type-guard

Validate before calling

if (config.kit?.handle !== undefined && typeof config.kit.handle !== 'function') {
  throw new Error('kit.handle must be a function');
}

Type guard

function isFunction(v) {
  return typeof v === 'function';
}

Try / catch

try {
  build(config);
} catch (e) {
  if (String(e.message).includes('should be a function')) {
    console.error('Config hook is not a function — check for accidental invocation: use fn, not fn()');
  } else throw e;
}

Prevention

When it happens

Trigger: Assigning a non-function to a function-typed kit config option, e.g. `handle: './hooks'` (string) or `handle: myMiddleware()` (invoked result) instead of `handle: myMiddleware`.

Common situations: Accidentally invoking the hook function instead of passing it; importing the wrong export from hooks.server.js; passing an async wrapper incorrectly or forgetting the export in a re-export chain.

Related errors


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

Appendix: source

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

			// prettier-ignore
			const msg = options.length > 2
				? `${keypath} should be one of ${options.slice(0, -1).map(input => `"${input}"`).join(', ')} or "${options[options.length - 1]}"`
				: `${keypath} should be either "${options[0]}" or "${options[1]}"`;

			throw new Error(msg);
		}
		return input;
	});
}

/**
 * @param {(...args: any) => any} fallback
 * @returns {Validator}
 */
function fun(fallback) {
	return validate(fallback, (input, keypath) => {
		if (typeof input !== 'function') {
			throw new Error(`${keypath} should be a function, if specified`);
		}
		return input;
	});
}

function any() {
	return validate(undefined, (input) => input);
}

/**
 * @param {string} input
 * @param {string} keypath
 */
function assert_string(input, keypath) {
	if (typeof input !== 'string') {
		throw new Error(`${keypath} should be a string, if specified`);
	}
}

View on GitHub (pinned to 03f1687fe6)