emberjs/ember.js · error · Error

Defining a route serializer on route '${name}' outside an En

Error message

Defining a route serializer on route '${name}' outside an Engine is not allowed.

What it means

In Ember's routing DSL, a custom serialize function may only be defined for routes inside an Engine (where it feeds addRouteForEngine). Defining serialize on a normal route map entry outside an engine is invalid because top-level routes serialize via the route's own serialize hook, so the DSL throws.

Source

Thrown at packages/@ember/routing/lib/dsl.ts:148

    url: string,
    name: string,
    callback?: MatchCallback,
    // eslint-disable-next-line @typescript-eslint/no-empty-object-type
    serialize?: (model: {}, params: string[]) => { [key: string]: unknown | undefined }
  ): void {
    let parts = name.split('.');

    if (this.options.engineInfo) {
      let localFullName = name.slice(this.options.engineInfo.fullName.length + 1);
      let routeInfo: EngineRouteInfo = Object.assign({ localFullName }, this.options.engineInfo);

      if (serialize) {
        routeInfo.serializeMethod = serialize;
      }

      this.options.addRouteForEngine(name, routeInfo);
    } else if (serialize) {
      throw new Error(
        `Defining a route serializer on route '${name}' outside an Engine is not allowed.`
      );
    }

    if (url === '' || url === '/' || parts[parts.length - 1] === 'index') {
      this.explicitIndex = true;
    }

    this.matches.push(url, name, callback);
  }

  generate(): MatchCallback {
    let dslMatches = this.matches;

    if (!this.explicitIndex) {
      this.route('index', { path: '/' });
    }

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Remove the serialize option and define serialize as a method on the Route class instead
  2. Only pass serialize for routes registered via addRouteForEngine inside engines
  3. Move the route into an engine if engine-specific serialization is required

Example fix

// before
this.route('post', { serialize: mySerializer });
// after
this.route('post');
// and in the route:
// export default class PostRoute extends Route { serialize(model) { return { id: model.id }; } }
Defensive patterns

Strategy: validation

Validate before calling

if (serialize && !isEngineContext) { throw new Error('serialize option only allowed inside engines'); }

Type guard

function canPassSerialize(dslOptions) { return typeof dslOptions.addRouteForEngine === 'function'; }

Try / catch

try { buildRouteMap(dsl); } catch (e) { if (/route serializer .* outside an Engine/.test(e.message)) stripSerializeOptionsAndRebuild(); else throw e; }

Prevention

When it happens

Trigger: Using dsl.route('path', { serialize: fn }) (via mount/branch APIs) where the dsl is not an engine context — i.e. options.addRouteForEngine is absent and serialize was supplied to push().

Common situations: Passing a serialize option when manually building a route map or in addons that manipulate the DSL; code written for ember-engines reused in a non-engine app.

Related errors


AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01). Data as JSON: /api/errors/75e39be550dabaaf. Report an issue: GitHub.