immich-app/immich · warning

Skipping invalid file upload route

Error message

Skipping invalid file upload route: ${route}

What it means

The file-upload interceptor only applies Multer handling to routes registered as file-upload routes. When the current route is not found in the configured file-upload routes, it logs this warning and passes the request through unmodified. It is a configuration mismatch between the interceptor registration and the actual route, not a thrown error.

Solutions

  1. Register the route in the file-upload interceptor's configured route list
  2. Apply the interceptor only to the specific upload controllers/routes via @UseInterceptors instead of globally
  3. Verify the route path used at runtime matches the configured route string (check controller path and method path)
  4. If the route is intentionally not an upload route, ignore the warning

Example fix

// before
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(FileUploadInterceptor).forRoutes('*');
  }
}
// after
@UseInterceptors(FileUploadInterceptor)
@Controller('assets')
export class AssetController {
  @Post('upload')
  upload(@UploadedFile() file: Express.Multer.File) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

const isUploadRoute = (route: string, uploadRoutes: readonly string[]) => uploadRoutes.includes(route);
if (!isUploadRoute(route, configuredUploadRoutes)) {
  throw new Error(`Route ${route} is not registered for file upload — add it to the interceptor config`);
}

Type guard

function isFileUploadRoute(route: string, routes: readonly string[]): route is typeof routes[number] {
  return (routes as readonly string[]).includes(route);
}

Prevention

When it happens

Trigger: A request hits a route where intercept() cannot resolve the route path in the configured file-upload routes map, or the interceptor is applied globally to non-upload routes.

Common situations: Adding new upload endpoints without updating the file-upload route configuration; mounting the interceptor globally instead of per-route; typos or missing route registrations; renaming a controller route without updating config.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/05e1a33d1597dab1. Report an issue: GitHub.

Appendix: source

Thrown at server/src/middleware/file-upload.interceptor.ts:83

        { name: UploadFieldName.ASSET_DATA, maxCount: 1 },
        { name: UploadFieldName.SIDECAR_DATA, maxCount: 1 },
      ]),
    };
  }

  async intercept(context: ExecutionContext, next: CallHandler<any>): Promise<Observable<any>> {
    const context_ = context.switchToHttp();
    const route = this.reflect.get<string>(PATH_METADATA, context.getClass());

    const handler: RequestHandler | null = this.getHandler(route as RouteKey);
    if (handler) {
      await new Promise<void>((resolve, reject) => {
        const next: NextFunction = (error) => (error ? reject(transformException(error)) : resolve());
        const maybePromise = handler(context_.getRequest(), context_.getResponse(), next);
        Promise.resolve(maybePromise).catch((error) => reject(error));
      });
    } else {
      this.logger.warn(`Skipping invalid file upload route: ${route}`);
    }

    return next.handle();
  }

  private fileFilter(request: AuthRequest, file: Express.Multer.File, callback: multer.FileFilterCallback) {
    try {
      callback(null, this.assetService.canUploadFile(asUploadRequest(request, file)));
    } catch (error: Error | any) {
      callback(error);
    }
  }

  private handleFile(request: AuthRequest, file: Express.Multer.File, callback: Callback<Partial<ImmichFile>>) {
    request.on('error', (error) => {
      if ('code' in error && error.code === 'ECONNRESET') {
        this.logger.debug('Upload was cancelled');
      } else {

View on GitHub (pinned to e55ac299a4)