Skip to content

[bug] MistralProvider throws cryptic null-check crash instead of ArgumentError when API key is missing #112

@RandalSchwartz

Description

@RandalSchwartz

When initializing MistralProvider without a MISTRAL_API_KEY environment variable or an explicit apiKey, creating a model crashes with a cryptic Null check operator used on a null value error instead of the clean, user-friendly ArgumentError thrown by other providers (like Google or Anthropic).

This issue was discovered while experimenting with the antigravity-cli (agy CLI) agent, and still needs repo-side verification and fixing.


Root Cause Analysis

In packages/dartantic_ai/lib/src/providers/mistral_provider.dart, the MistralProvider constructor omits passing apiKeyName: defaultApiKeyName to its parent Provider constructor:

  MistralProvider({String? apiKey, super.headers})
    : super(
        apiKey: apiKey ?? tryGetEnv(defaultApiKeyName),
        name: 'mistral',
        displayName: 'Mistral',
        defaultModelNames: {
          ModelKind.chat: 'mistral-medium-latest',
          ModelKind.embeddings: 'mistral-embed',
        },
        baseUrl: null,
        aliases: ['mistralai'],
        // apiKeyName: defaultApiKeyName is missing here!
      );

As a result:

  1. apiKeyName evaluates to null.
  2. In createChatModel(), the following validation check is completely bypassed because apiKeyName != null is false:
    if (apiKeyName != null && (apiKey == null || apiKey!.isEmpty)) {
      throw ArgumentError('$apiKeyName is required for $displayName provider');
    }
  3. The method then tries to construct MistralChatModel and applies a bang operator to apiKey (which is null):
    return MistralChatModel(
      ...
      apiKey: apiKey!, // <-- Crashes here with Null check operator used on a null value
      ...
    );

Suggested Fix

  1. Surgically fix the constructor:
    Update packages/dartantic_ai/lib/src/providers/mistral_provider.dart to specify the missing parameter:

    MistralProvider({String? apiKey, super.headers})
      : super(
          apiKey: apiKey ?? tryGetEnv(defaultApiKeyName),
          name: 'mistral',
          displayName: 'Mistral',
          defaultModelNames: {
            ModelKind.chat: 'mistral-medium-latest',
            ModelKind.embeddings: 'mistral-embed',
          },
          baseUrl: null,
          aliases: ['mistralai'],
          apiKeyName: defaultApiKeyName, // <-- Fix
        );
  2. Add unit test coverage:
    Add a regression test in packages/dartantic_ai/test/provider_initialization_test.dart to ensure it resolves correctly and throws a clean ArgumentError:

    test('Mistral provider requires MISTRAL_API_KEY to create chat models', () {
      final mistralProvider = Agent.getProvider('mistral');
    
      expect(
        mistralProvider.createChatModel,
        throwsA(
          isA<ArgumentError>().having(
            (e) => e.message,
            'message',
            contains('MISTRAL_API_KEY is required'),
          ),
        ),
      );
    });

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions