You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fastify-React应用配置环境变量时出现AVV_ERR_PLUGIN_NOT_VALID错误求助

问题:Fastify中配置环境变量触发AVV_ERR_PLUGIN_NOT_VALID错误

在Fastify-React应用中配置环境变量时,运行代码触发了AVV_ERR_PLUGIN_NOT_VALID错误,请求分析原因并解决。

代码示例

const fastify = require('fastify')({ 
    logger: {
      level: 'debug',
    }
  });
  
  console.log('hello from server.js 1 !');
  
  // setting up cors:
  const cors = require("@fastify/cors");  
  fastify.register(cors, { origin: "*" });
  
  // setting up environment variables
  const fastifyEnv = require('@fastify/env');
  const envSchema = {
    type: 'object',
    required: ['YOUTUBE_DATA_API_KEY', 'TESTVAR', 'GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET', 'JWT_SECRET'],
    properties: {
      YOUTUBE_DATA_API_KEY: { type: 'string' },
      TESTVAR: { type: 'string' },
      GOOGLE_CLIENT_ID: { type: 'string' },
      GOOGLE_CLIENT_SECRET: { type: 'string' },
      JWT_SECRET: { type: 'string' }     
    } 
  };
  const options = {
    confKey: 'config', 
    schema: envSchema,
    dotenv: {
      path: `${__dirname}/.env`,
      debug: true
    }
  };
  
  fastify.register(fastifyEnv, options);
  
  fastify.ready(err => {
    if (err) throw err;
    console.log('fastify.config at server.js: ', fastify.config);
  
    const fastifyJwt = require('@fastify/jwt');
    fastify.register(fastifyJwt, { secret: fastify.config.JWT_SECRET });
  });
  
  // setting up authentication:
  fastify.decorate('verifyJWTandLevel', (request, reply, done) => {
    done();
  }).decorate('verifyUserAndPassword', (request, reply, done) => {
    done();
  }).register(require('@fastify/auth')).after(() => {
    fastify.route({
      method: 'POST',
      url: '/auth-multiple',
      preHandler: fastify.auth([fastify.verifyJWTandLevel, fastify.verifyUserAndPassword]),
      handler: (req, reply) => {
        req.log.info('Auth route');
        reply.send({ hello: 'world' });
      }
    });
  });
  
  // other setup...
  
  const videoRouter = require('./src/routes/videoRouter');
  fastify.register(videoRouter, { prefix: '/api/v1' });
  
  fastify.get('/', (request, reply) => {
    console.log('hello from server.js 5000!');
    reply.send({ hello: 'fastify server at 5000!' });
  });
  
  // Start function
  const start = async () => {
    try {
      await fastify.listen({
        port: 5000,
        address: '0.0.0.0'
      });
      console.log('Server is running on port 5000');
    } catch (err) {
      fastify.log.error(err);
      process.exit(1);
    }
  };
 
  fastify.ready(err => {
    if (err) throw err;
    start();
  });

错误栈信息

[FASTIFY] AvvioError [Error]: Root plugin has already booted
[FASTIFY]     at Boot._addPlugin (/home/totoro/vc_app/vc-app/node_modules/avvio/boot.js:244:11)
[FASTIFY]     at Boot.use (/home/totoro/vc_app/vc-app/node_modules/avvio/boot.js:216:25)
[FASTIFY]     at server. [as register] (/home/totoro/vc_app/vc-app/node_modules/avvio/boot.js:40:14)
[FASTIFY]     at /home/totoro/vc_app/vc-app/backend/server.js:42:13
[FASTIFY]     at manageErr (/home/totoro/vc_app/vc-app/node_modules/fastify/fastify.js:595:11)
[FASTIFY]     at exit (/home/totoro/vc_app/vc-app/node_modules/fastify/lib/hooks.js:110:5)
[FASTIFY]     at manageTimeout (/home/totoro/vc_app/vc-app/node_modules/fastify/lib/hooks.js:127:11)
[FASTIFY]     at _encapsulateThreeParam (/home/totoro/vc_app/vc-app/node_modules/avvio/boot.js:562:7)
[FASTIFY]     at Boot.timeoutCall (/home/totoro/vc_app/vc-app/node_modules/avvio/boot.js:458:5)
[FASTIFY]     at Boot.callWithCbOrNextTick (/home/totoro/vc_app/vc-app/node_modules/avvio/boot.js:440:19) {
[FASTIFY]   code: 'AVV_ERR_PLUGIN_NOT_VALID'
原因与解决方案

错误原因

问题出在**fastify.ready回调中调用fastify.register(fastifyJwt)**。Fastify的ready事件是在所有插件加载、实例启动完成后触发的,此时根插件已经进入"booted"状态,无法再注册新插件,这就是AVV_ERR_PLUGIN_NOT_VALID错误的核心原因。

Fastify要求所有插件注册操作必须在实例启动前完成,ready回调只能用来执行启动后的初始化逻辑,不能添加新插件。

解决方案

将fastifyJwt的注册移到ready回调之外,利用Fastify的after钩子,确保在fastifyEnv加载完成后再注册fastifyJwt。

修改后的完整代码

const fastify = require('fastify')({ 
  logger: {
    level: 'debug',
  }
});

console.log('hello from server.js 1 !');

// setting up cors:
const cors = require("@fastify/cors");  
fastify.register(cors, { origin: "*" });

// setting up environment variables
const fastifyEnv = require('@fastify/env');
const envSchema = {
  type: 'object',
  required: ['YOUTUBE_DATA_API_KEY', 'TESTVAR', 'GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET', 'JWT_SECRET'],
  properties: {
    YOUTUBE_DATA_API_KEY: { type: 'string' },
    TESTVAR: { type: 'string' },
    GOOGLE_CLIENT_ID: { type: 'string' },
    GOOGLE_CLIENT_SECRET: { type: 'string' },
    JWT_SECRET: { type: 'string' }     
  } 
};
const options = {
  confKey: 'config', 
  schema: envSchema,
  dotenv: {
    path: `${__dirname}/.env`,
    debug: true
  }
};

// 注册fastifyEnv后,用after钩子确保环境变量加载完成再注册fastifyJwt
fastify.register(fastifyEnv, options).after(() => {
  const fastifyJwt = require('@fastify/jwt');
  fastify.register(fastifyJwt, { secret: fastify.config.JWT_SECRET });
});

// setting up authentication:
fastify.decorate('verifyJWTandLevel', (request, reply, done) => {
  done();
}).decorate('verifyUserAndPassword', (request, reply, done) => {
  done();
}).register(require('@fastify/auth')).after(() => {
  fastify.route({
    method: 'POST',
    url: '/auth-multiple',
    preHandler: fastify.auth([fastify.verifyJWTandLevel, fastify.verifyUserAndPassword]),
    handler: (req, reply) => {
      req.log.info('Auth route');
      reply.send({ hello: 'world' });
    }
  });
});

// other setup...

const videoRouter = require('./src/routes/videoRouter');
fastify.register(videoRouter, { prefix: '/api/v1' });

fastify.get('/', (request, reply) => {
  console.log('hello from server.js 5000!');
  reply.send({ hello: 'fastify server at 5000!' });
});

// Start function
const start = async () => {
  try {
    await fastify.listen({
      port: 5000,
      address: '0.0.0.0'
    });
    console.log('Server is running on port 5000');
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

// 直接用listen启动,listen内部会自动等待所有插件加载完成
start();

关键修改点

  1. 移除了第一个fastify.ready回调,改用fastify.register(fastifyEnv, options).after()钩子,确保fastifyEnv加载完成后再注册fastifyJwt,此时环境变量已可用。
  2. 移除了第二个fastify.ready回调,直接调用start()函数,因为fastify.listen()内部会自动处理插件加载完成的逻辑,无需手动监听ready事件。

内容的提问来源于stack exchange,提问作者Toto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:53:11