danny-avila/LibreChat · error

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

Error message

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

What it means

STTService.getProviderSchema throws when appConfig.speech.stt is falsy. The whole STT subsystem reads its wiring from the `speech.stt` block resolved via getAppConfig (typically librechat.yaml, filtered by role/userId/tenantId). An absent or empty block means no provider can be selected, so the request is rejected before any strategy lookup.

Source

Thrown at api/server/services/Files/Audio/STTService.js:155

  }

  /**
   * Retrieves the configured STT provider and its schema.
   * @param {ServerRequest} req - The request object.
   * @returns {Promise<[string, Object, (string[]|undefined)]>} A promise that resolves to the provider name, its schema, and the section-level allowedAddresses exemption list.
   * @throws {Error} If no STT schema is set, multiple providers are set, or no provider is set.
   */
  async getProviderSchema(req) {
    const appConfig =
      req.config ??
      (await getAppConfig({
        role: req?.user?.role,
        userId: req?.user?.id,
        tenantId: req?.user?.tenantId,
      }));
    const sttSchema = appConfig?.speech?.stt;
    if (!sttSchema) {
      throw new Error(
        'No STT schema is set. Did you configure STT in the custom config (librechat.yaml)?',
      );
    }

    const providers = Object.entries(sttSchema).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.',
      );
    }

    const [provider, schema] = providers[0];
    return [provider, schema, sttSchema.allowedAddresses];

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Add a `speech.stt` block with exactly one populated provider (e.g. openai or azureOpenAI) to librechat.yaml.
  2. Confirm librechat.yaml is mounted and parsed — check startup logs for the config load line.
  3. Restart the API server so getAppConfig picks up the change.

Example fix

# before
speech: {}

# after (librechat.yaml)
speech:
  stt:
    openai:
      apiKey: '${STT_API_KEY}'
      model: 'whisper-1'
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Prevention

When it happens

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

Common situations: STT enabled in the client UI but never configured server-side; librechat.yaml not mounted into the container; config file path misconfigured; tenant-scoped override returns an empty speech block; upgrade that renamed the config key.

Related errors


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