BerriAI/litellm · error · HTTPException

str(e)

Error message

str(e)

What it means

Catch-all 500 from list_plugins (GET /claude-code/plugins). Any non-HTTPException during the Prisma find_many over the plugin table, manifest parsing, or the sort by created_at is logged as 'Error listing plugins' and surfaced as a bare str(e) 500 — the least informative of the module's error messages, so the log line is essential.

Source

Thrown at litellm/proxy/anthropic_endpoints/claude_code_endpoints/claude_code_marketplace.py:397

                    enabled=p.enabled,
                    created_at=p.created_at.isoformat() if p.created_at else None,
                    updated_at=p.updated_at.isoformat() if p.updated_at else None,
                )
            )

        # Sort by created_at descending (newest first)
        plugin_list.sort(key=lambda x: x.created_at or "", reverse=True)

        return ListPluginsResponse(
            plugins=plugin_list,
            count=len(plugin_list),
        )

    except HTTPException:
        raise
    except Exception as e:
        verbose_proxy_logger.exception("Error listing plugins: %s", e)
        raise HTTPException(
            status_code=500,
            detail={"error": str(e)},
        )


@router.get(
    "/claude-code/plugins/{plugin_name}",
    tags=["Claude Code Marketplace"],
    dependencies=[Depends(user_api_key_auth)],
)
async def get_plugin(
    plugin_name: str,
    user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
):
    """
    Get details of a specific plugin.

    Parameters:

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Check the proxy logs for 'Error listing plugins' to get the actual traceback.
  2. For a missing-table/relation error, restart the proxy with DATABASE_URL configured so Prisma migrations run and create the plugin table.
  3. For a JSONDecodeError, inspect manifest_json values in the plugin table and fix or delete the offending rows, then re-register those plugins.
  4. For connection errors, restore DB connectivity and retry — this GET is read-only and safe to retry.
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(3):
    resp = client.get(f"{base}/claude-code/plugins", headers=hdr)
    if resp.status_code == 200:
        return resp.json()["plugins"]
    if resp.status_code == 500 and attempt < 2:
        time.sleep(2 ** attempt)  # transient DB issue; read-only so retry is safe
        continue
    resp.raise_for_status()

Prevention

When it happens

Trigger: GET /claude-code/plugins when litellm_claudecodeplugintable is missing (un-migrated schema), when the DB connection has died, or when a row's manifest_json is invalid JSON that json.loads chokes on while building PluginListItem.

Common situations: Immediately after a LiteLLM version upgrade that added the marketplace feature, hitting the admin list endpoint before migrations ran; polling scripts that discover the DB was restarted; a plugin row inserted by hand or by a broken earlier registration.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/941ccf7e190a06b9. Report an issue: GitHub.