usememos/memos · error

OpenAI API key is required

Error message

OpenAI API key is required

What it means

Returned by openai.New (internal/ai/stt/openai) when ai.ProviderConfig.APIKey is the empty string. The OpenAI-compatible SDK client is constructed with WithAPIKey(cfg.APIKey), and an empty key would only fail later at the HTTP layer with 401s, so construction fails fast instead.

Source

Thrown at internal/ai/stt/openai/openai.go:34

	"github.com/usememos/memos/internal/ai"
	"github.com/usememos/memos/internal/ai/stt"
)

const defaultEndpoint = "https://api.openai.com/v1"

// Transcriber implements stt.Transcriber for OpenAI-compatible STT endpoints.
type Transcriber struct {
	client openaisdk.Client
}

// New constructs a Transcriber from a provider config.
func New(cfg ai.ProviderConfig, options stt.Options) (*Transcriber, error) {
	endpoint, err := normalizeEndpoint(cfg.Endpoint)
	if err != nil {
		return nil, err
	}
	if cfg.APIKey == "" {
		return nil, errors.New("OpenAI API key is required")
	}
	return &Transcriber{
		client: openaisdk.NewClient(
			openaioption.WithAPIKey(cfg.APIKey),
			openaioption.WithBaseURL(endpoint),
			openaioption.WithHTTPClient(options.HTTPClient),
		),
	}, nil
}

// Transcribe sends the audio to /audio/transcriptions.
func (t *Transcriber) Transcribe(ctx context.Context, req stt.Request) (*stt.Response, error) {
	if strings.TrimSpace(req.Model) == "" {
		return nil, errors.New("model is required")
	}
	if req.Audio == nil {
		return nil, errors.New("audio is required")
	}

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Set the API key in the AI provider settings for the OpenAI-compatible provider and retry.
  2. Verify the secret actually reaches the process (container env, secret store) — reference by name, never log it.
  3. For local no-auth endpoints, pass any non-empty placeholder key if your setup allows it.
  4. Confirm you selected the right provider type; a dedicated STT provider may be the wrong choice (see ai.ErrSTTNotSupported).

Example fix

// before
cfg := ai.ProviderConfig{Endpoint: "https://api.openai.com/v1"}
t, err := openai.New(cfg, opts) // err: OpenAI API key is required

// after
cfg := ai.ProviderConfig{Endpoint: "https://api.openai.com/v1", APIKey: os.Getenv("MEMOS_OPENAI_API_KEY")}
if cfg.APIKey == "" {
  return errors.New("MEMOS_OPENAI_API_KEY not set")
}
t, err := openai.New(cfg, opts)
Defensive patterns

Strategy: validation

Validate before calling

// Go — gate on the key by name, never log it
if strings.TrimSpace(cfg.APIKey) == "" {
  return errors.New("AI provider API key is not configured (check provider settings / injected secret)")
}
_, err := openai.New(cfg, opts)

Try / catch

t, err := openai.New(cfg, opts)
if err != nil {
  if strings.Contains(err.Error(), "API key is required") {
    return status.Errorf(codes.FailedPrecondition, "AI provider not configured: add an API key in settings")
  }
  return err
}

Prevention

When it happens

Trigger: Creating the OpenAI STT transcriber with a provider config whose APIKey was never populated — e.g., the Memos AI provider settings saved without a key, or the env/source feeding ProviderConfig returned an empty string. Happens on the first transcription attempt or at provider construction.

Common situations: Fresh AI provider setup where the key field was left blank; secret env var (OPENAI_API_KEY) not injected into the container; using a local OpenAI-compatible server (whisper.cpp, vLLM) that needs no auth but the code path still requires a non-empty key string.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/98bf6b20ecff4eef. Report an issue: GitHub.