fastify/fastify · critical · TypeError

FST_ERR_OPTIONS_NOT_OBJ

FST_ERR_OPTIONS_NOT_OBJ

Error message

Options must be an object

What it means

Thrown by processOptions (fastify.js:859-860) when the argument passed to the fastify() factory is truthy but not of type 'object'. The guard `options && typeof options !== 'object'` catches strings, numbers, booleans, and functions. (null and undefined pass through; arrays pass because typeof array === 'object', though they will fail downstream.) Fastify requires a plain options object describing logger, body limits, AJV config, etc.

Source

Thrown at fastify.js:860

      this[kSupportedHTTPMethods].bodywith.delete(method)
      this[kSupportedHTTPMethods].bodyless.add(method)
    }

    const _method = method.toLowerCase()
    if (!this.hasDecorator(_method)) {
      this.decorate(_method, function (url, options, handler) {
        return router.prepareRoute.call(this, { method, url, options, handler })
      })
    }

    return this
  }
}

function processOptions (options, defaultRoute, onBadUrl, onMaxParamLength) {
  // Options validations
  if (options && typeof options !== 'object') {
    throw new FST_ERR_OPTIONS_NOT_OBJ()
  } else {
    // Shallow copy options object to prevent mutations outside of this function
    options = Object.assign({}, options)
  }

  if (
    (options.querystringParser && typeof options.querystringParser !== 'function') ||
    (
      options.routerOptions?.querystringParser &&
      typeof options.routerOptions.querystringParser !== 'function'
    )
  ) {
    throw new FST_ERR_QSP_NOT_FN(typeof (options.querystringParser ?? options.routerOptions.querystringParser))
  }

  if (options.schemaController && options.schemaController.bucket && typeof options.schemaController.bucket !== 'function') {
    throw new FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN(typeof options.schemaController.bucket)
  }

View on GitHub (pinned to 7299a57d3f)

Solutions

  1. Pass a plain object: `const app = fastify({ logger: true })`.
  2. If reading config from env, build the object explicitly: `fastify({ port: Number(process.env.PORT) })`.
  3. Pass nothing (fastify()) or null for defaults rather than a scalar.

Example fix

// before
const app = fastify(process.env.PORT) // PORT is a string

// after
const app = fastify({ port: Number(process.env.PORT) })
Defensive patterns

Strategy: type-guard

Validate before calling

function buildFastify(opts) {
  if (opts != null && (typeof opts !== 'object' || Array.isArray(opts))) {
    throw new TypeError('fastify() expects a plain options object, got ' + typeof opts)
  }
  return fastify(opts || {})
}

Type guard

const isPlainOptions = (o) => o == null || (typeof o === 'object' && !Array.isArray(o))

Try / catch

try {
  const app = fastify(maybeOpts)
} catch (err) {
  if (err.code === 'FST_ERR_OPTIONS_NOT_OBJ') {
    throw new TypeError('fastify() options must be a plain object, got ' + typeof maybeOpts)
  }
  throw err
}

Prevention

When it happens

Trigger: Calling `fastify('3000')`, `fastify(3000)`, `fastify(true)`, or `fastify(() => {})` instead of `fastify({ port: 3000 })`.

Common situations: Confusing the factory with frameworks that accept a port string; passing a parsed CLI arg without coercing to an object; accidentally forwarding a config value instead of the config object.

Related errors


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