nestjs/nest · error · NotFoundException

${id}

Error message

${id}

What it means

NestJS NotFoundException thrown at sample/23-graphql-code-first/src/recipes/recipes.resolver.ts:19 inside the `recipe(id)` @Query resolver when RecipesService.findOneById(id) returns a falsy value. Because it is constructed as `new NotFoundException(id)`, the raw id string becomes the error message — hence the message is literally `${id}`. It signals that no recipe with the requested identifier exists in the in-memory store.

Source

Thrown at sample/23-graphql-code-first/src/recipes/recipes.resolver.ts:19

import { NotFoundException } from '@nestjs/common';
import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
import { PubSub } from 'graphql-subscriptions';
import { NewRecipeInput } from './dto/new-recipe.input';
import { RecipesArgs } from './dto/recipes.args';
import { Recipe } from './models/recipe.model';
import { RecipesService } from './recipes.service';

const pubSub = new PubSub();

@Resolver(of => Recipe)
export class RecipesResolver {
  constructor(private readonly recipesService: RecipesService) {}

  @Query(returns => Recipe)
  async recipe(@Args('id') id: string): Promise<Recipe> {
    const recipe = await this.recipesService.findOneById(id);
    if (!recipe) {
      throw new NotFoundException(id);
    }
    return recipe;
  }

  @Query(returns => [Recipe])
  recipes(@Args() recipesArgs: RecipesArgs): Promise<Recipe[]> {
    return this.recipesService.findAll(recipesArgs);
  }

  @Mutation(returns => Recipe)
  async addRecipe(
    @Args('newRecipeData') newRecipeData: NewRecipeInput,
  ): Promise<Recipe> {
    const recipe = await this.recipesService.create(newRecipeData);
    pubSub.publish('recipeAdded', { recipeAdded: recipe });
    return recipe;
  }

View on GitHub (pinned to 6ec0e2783d)

Solutions

  1. Verify the id against the store before assuming the client is wrong — check RecipesService.findOneById's data source.
  2. Return null instead of throwing if your GraphQL schema declares the field as nullable, so the client gets partial data rather than an error.
  3. Improve the message: pass a human-readable string (`new NotFoundException(`Recipe ${id} not found`)`) instead of the bare id.
  4. On the client, treat the 404 as data and surface a friendly 'not found' UI.

Example fix

// before
const recipe = await this.recipesService.findOneById(id);
if (!recipe) {
  throw new NotFoundException(id);
}

// after
const recipe = await this.recipesService.findOneById(id);
if (!recipe) {
  throw new NotFoundException(`Recipe with id "${id}" not found`);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before resolving, check the store directly (or a lightweight exists() method).
const exists = await recipesService.existsById(id);
if (!exists) {
  // render 'not found' UI without triggering the throwing resolver
}

Type guard

function isRecipe(v: unknown): v is Recipe {
  return typeof v === 'object' && v !== null
    && typeof (v as any).id === 'string'
    && typeof (v as any).title === 'string';
}

Try / catch

// Apollo Client
try {
  const { data, errors } = await client.query({ query: RECIPE, variables: { id } });
} catch (e) {
  const notFound = e.graphQLErrors?.some(
    (g: any) => g.extensions?.code === 'NOT_FOUND' || /not found/i.test(g.message),
  );
  if (notFound) navigate('/404');
}

Prevention

When it happens

Trigger: GraphQL query `query { recipe(id: "<id-not-in-store>") { id title } }` — findOneById returns null/undefined, so the resolver throws 404. Also fires for malformed ids the service treats as absent (e.g., wrong UUID format).

Common situations: Client holds a stale id after removeRecipe was called; typo/hard-coded id in a test; in-memory sample store reset on HMR/restart so previously valid ids vanish; id format mismatch (service expects a different identifier scheme than the client sends).

Related errors


AI-assisted analysis of nestjs/nest@6ec0e2783d (2026-08-03). Data as JSON: /data/errors/197a4fba09917efe.json. Report an issue: GitHub.