Skip to content

Bug: /api/v1/prompts/models returns HTTP 500 when PDD_MODEL_DEFAULT is not set #85

@Serhan-Asad

Description

@Serhan-Asad

Description

The /api/v1/prompts/models endpoint in pdd connect crashes with HTTP 500 for all users who don't have the PDD_MODEL_DEFAULT environment variable set.

Since PDD_MODEL_DEFAULT is undocumented and not configured by pdd setup, .pddrc, .env.example, or any setup path, this effectively means every user hits this bug when the frontend calls this endpoint.

Root Cause

DEFAULT_BASE_MODEL is None when the env var is unset (llm_invoke.py:635):

DEFAULT_BASE_MODEL = os.getenv("PDD_MODEL_DEFAULT", None)

The endpoint passes this directly to a Pydantic model that requires str (server/routes/prompts.py:94-97):

class ModelsResponse(BaseModel):
    models: list[ModelInfo] = Field(...)
    default_model: str = Field(...)  # rejects None

Result: ValidationError → HTTP 500.

Reproduction

# 1. Ensure PDD_MODEL_DEFAULT is not set (default for all users)
unset PDD_MODEL_DEFAULT

# 2. Start the server
pdd connect

# 3. Hit the endpoint
curl http://127.0.0.1:9876/api/v1/prompts/models

Response:

{
  "detail": "Error getting available models: 1 validation error for ModelsResponse\ndefault_model\n  Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]"
}

Why Tests Don't Catch This

The existing test at tests/server/routes/test_prompts.py:129 mocks DEFAULT_BASE_MODEL to "claude-sonnet-4-20250514", so it never sees the None case:

mock_llm_invoke.DEFAULT_BASE_MODEL = "claude-sonnet-4-20250514"

Impact

  • The Dev Units view model selector fails to load for every user
  • PDD_MODEL_DEFAULT is not documented anywhere (README, help text, setup guide, .env.example)
  • No setup path configures it — users have no way to know it exists

Suggested Fix

Either:

  1. Make default_model optional: default_model: Optional[str] = Field(None, ...)
  2. Or fall back to the first model from CSV when DEFAULT_BASE_MODEL is None:
    default_model=DEFAULT_BASE_MODEL or (models[0].name if models else "")

Option 2 is better UX since the frontend always gets a usable default.

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