danny-avila/LibreChat · error

No TTS schema is set. Did you configure TTS in the custom co

Error message

No TTS schema is set. Did you configure TTS in the custom config (librechat.yaml)?

What it means

TTSService.getProvider throws when appConfig.speech.tts is falsy. The TTS subsystem reads its wiring from the `speech.tts` block resolved via getAppConfig (typically librechat.yaml). An absent or empty block means no provider can be selected.

Source

Thrown at api/server/services/Files/Audio/TTSService.js:51

   * @static
   * @async
   * @returns {Promise<TTSService>} The TTSService instance.
   * @throws {Error} If the custom config is not found.
   */
  static async getInstance() {
    return new TTSService();
  }

  /**
   * Retrieves the configured TTS provider.
   * @param {AppConfig | null | undefined} [appConfig] - The app configuration object.
   * @returns {string} The name of the configured provider.
   * @throws {Error} If no provider is set or multiple providers are set.
   */
  getProvider(appConfig) {
    const ttsSchema = appConfig?.speech?.tts;
    if (!ttsSchema) {
      throw new Error(
        'No TTS schema is set. Did you configure TTS in the custom config (librechat.yaml)?',
      );
    }
    const providers = Object.entries(ttsSchema).filter(
      ([key, value]) => key !== 'allowedAddresses' && Object.keys(value).length > 0,
    );

    if (providers.length !== 1) {
      throw new Error(
        providers.length > 1
          ? 'Multiple providers are set. Please set only one provider.'
          : 'No provider is set. Please set a provider.',
      );
    }
    return providers[0][0];
  }

  /**

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Add a `speech.tts` block with exactly one populated provider (openai, azureOpenAI, elevenlabs, or localai) to librechat.yaml.
  2. Confirm librechat.yaml is mounted and parsed (startup log).
  3. Restart the API server so getAppConfig reloads.

Example fix

# before
speech: {}

# after (librechat.yaml)
speech:
  tts:
    openai:
      apiKey: '${TTS_API_KEY}'
      model: 'tts-1'
      voices: ['alloy', 'echo']
Defensive patterns

Strategy: validation

Validate before calling

const appConfig = await getAppConfig({ role, userId, tenantId });
const tts = appConfig?.speech?.tts;
if (!tts) {
  return res.status(503).json({ error: 'TTS is not configured on this server.' });
}

Type guard

/** @param {unknown} c */
function hasTtsSchema(c) {
  return !!c && typeof c === 'object' && 'speech' in c
    && !!c.speech && typeof c.speech === 'object'
    && 'tts' in c.speech && !!c.speech.tts
    && typeof c.speech.tts === 'object';
}

Prevention

When it happens

Trigger: Any TTS request (POST /api/speech/tts) when librechat.yaml has no `speech.tts` section, or role/tenant-scoped config returns an object whose `speech.tts` is undefined/null.

Common situations: TTS enabled in the client but never configured server-side; librechat.yaml not mounted; config key renamed during an upgrade; tenant override returns empty speech.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/a620b3f70bf6009f. Report an issue: GitHub.