fastify/fastify · error · Error

FST_ERR_CTP_ALREADY_PRESENT

FST_ERR_CTP_ALREADY_PRESENT

Error message

Content type parser '%s' already present.

What it means

Thrown by ContentTypeParser.prototype.add (content-type-parser.js:58-59) when a parser is already registered for the given content type. existingParser() returns true if a custom parser was set, or if the type is one of the built-ins ('application/json', 'text/plain') that already have default parsers. The message includes the offending content type via %s.

Source

Thrown at lib/content-type-parser.js:59

  this.cache = new Fifo(100)
}

ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
  const contentTypeIsString = typeof contentType === 'string'

  if (contentTypeIsString) {
    contentType = contentType.trim().toLowerCase()
    if (contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
  } else if (!(contentType instanceof RegExp)) {
    throw new FST_ERR_CTP_INVALID_TYPE()
  }

  if (typeof parserFn !== 'function') {
    throw new FST_ERR_CTP_INVALID_HANDLER()
  }

  if (this.existingParser(contentType)) {
    throw new FST_ERR_CTP_ALREADY_PRESENT(contentType)
  }

  if (opts.parseAs !== undefined) {
    if (opts.parseAs !== 'string' && opts.parseAs !== 'buffer') {
      throw new FST_ERR_CTP_INVALID_PARSE_TYPE(opts.parseAs)
    }
  }

  const parser = new Parser(
    opts.parseAs === 'string',
    opts.parseAs === 'buffer',
    opts.bodyLimit,
    parserFn
  )

  if (contentType === '*') {
    this.customParsers.set('', parser)
  } else {

View on GitHub (pinned to 7299a57d3f)

Solutions

  1. Use a different content type, or remove the existing parser first with removeContentTypeParser before re-adding.
  2. To replace the default JSON/text parser, call addContentTypeParser once for that type (the defaults are replaceable once).
  3. Check with `fastify.hasContentTypeParser(type)` before registering to avoid collisions.

Example fix

// before
app.addContentTypeParser('application/json', { parseAs: 'string' }, myParser)
app.addContentTypeParser('application/json', { parseAs: 'string' }, other) // throws

// after
app.removeContentTypeParser('application/json')
app.addContentTypeParser('application/json', { parseAs: 'string' }, other)
Defensive patterns

Strategy: validation

Validate before calling

// Check existence before registering to avoid collisions.
function addParserIfMissing(app, type, opts, fn) {
  if (app.hasContentTypeParser(type)) {
    // For defaults, remove first; for custom, skip or replace deliberately
    app.removeContentTypeParser(type)
  }
  return app.addContentTypeParser(type, opts, fn)
}

Try / catch

try {
  app.addContentTypeParser(type, opts, fn)
} catch (err) {
  if (err.code === 'FST_ERR_CTP_ALREADY_PRESENT') {
    app.log.warn({ type }, 'parser already registered; skipping')
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: Calling `addContentTypeParser('application/json', ...)` a second time, or registering a parser for 'text/plain' when only the default exists (the default counts as present for this check unless you are replacing the default JSON/text parser — note existingParser special-cases the defaults to allow replacing them once).

Common situations: Two plugins both registering a parser for the same media type; re-registering after a hot-reload without a fresh instance; registering for 'application/json' forgetting Fastify already parses JSON.

Related errors


AI-assisted analysis of fastify/fastify@7299a57d3f (2026-08-03). Data as JSON: /data/errors/2882e8ccfc1b2baa.json. Report an issue: GitHub.