Troubleshooting Guide¶
Common issues and solutions for OSA community onboarding and operations.
Quick Diagnostic Checklist¶
Before diving into specific errors:
-
Validate your config:
-
Check environment variables:
If your community funds itself through OpenRouter instead, the variable is named
OPENROUTER_API_KEY_YOUR_COMMUNITY; everything below works the same way, against OpenRouter rather than Anthropic. -
Test API key:
-
Check server status:
Configuration Validation Errors¶
Error: YAML Syntax Error¶
Symptom:
Causes: - Incorrect indentation (must use spaces, not tabs) - Missing colon after key - Improper list formatting - Special characters not quoted
Solutions:
Check indentation:
# Wrong - using tabs
documentation:
- title: My Doc
# Correct - using spaces
documentation:
- title: My Doc
Quote special characters:
# Wrong - colon in unquoted string
description: HED: Event annotation
# Correct - quoted
description: "HED: Event annotation"
List formatting:
# Wrong - missing dash
cors_origins:
https://example.com
# Correct - with dash
cors_origins:
- https://example.com
Validation:
Error: Community ID must be kebab-case¶
Symptom:
Cause: Community ID contains uppercase letters, underscores, or invalid characters.
Solution:
# Wrong
id: MyProject
id: my_project
id: my.project
id: -myproject # Leading hyphen
# Correct
id: myproject
id: my-project
id: my-project-2024
Rules: - Lowercase letters only - Numbers allowed - Hyphens allowed (not leading/trailing) - No underscores, dots, or spaces
Error: Invalid CORS origin¶
Symptom:
Cause: CORS origin missing scheme or improperly formatted.
Solution:
# Wrong - missing scheme
cors_origins:
- example.com
- www.example.com
# Wrong - includes path
cors_origins:
- https://example.com/docs
# Correct
cors_origins:
- https://example.com
- https://www.example.com
- https://*.example.com
Common Mistakes: - Forgetting https:// prefix - Including path (/docs) - Including query string (?foo=bar) - Using * alone (not allowed) - A wildcard on a shared hosting domain, such as https://*.pages.dev, which authorizes every site on that platform
Error: Preload requires source_url¶
Symptom:
Cause: Document configured with preload: true but missing source_url field.
Solution:
# Wrong - preload without source_url
documentation:
- title: Core Docs
url: https://example.com/docs
preload: true
# Correct - source_url provided
documentation:
- title: Core Docs
url: https://example.com/docs
source_url: https://raw.githubusercontent.com/org/repo/main/docs.md
preload: true
Why: Preloaded documents are fetched and embedded in the system prompt. The source_url must point to the raw markdown or text content.
Error: Repository must be in 'org/repo' format¶
Symptom:
Cause: GitHub repository missing organization prefix.
Solution:
# Wrong - missing org
github:
repos:
- hed-specification
# Correct - org/repo format
github:
repos:
- hed-standard/hed-specification
Error: Invalid DOI format¶
Symptom:
Cause: DOI includes URL prefix or doesn't match expected format.
Solution:
# Wrong - includes prefix
citations:
dois:
- https://doi.org/10.1234/example
- doi.org/10.1234/example
# Correct - DOI only
citations:
dois:
- 10.1234/example
Valid DOI Format: - Must start with 10. - Format: 10.xxxx/yyyy - No URL prefixes
API Key Issues¶
Warning: API key env var not set¶
Symptom:
Impact: - Assistant will fall back to platform API key - Costs billed to platform, not your community - Shared rate limits apply
Solution:
For local testing:
For production (server):
Verify:
uv run osa validate src/assistants/myproject/config.yaml
# Should show: "✓ ANTHROPIC_API_KEY_MYPROJECT is set (Anthropic)"
The env var name must match ANTHROPIC_API_KEY_[A-Z0-9_]+, so that a config cannot point the assistant at an unrelated secret. A community whose config sets openrouter_api_key_env_var instead is reported the same way, as (OpenRouter), and its variable must match OPENROUTER_API_KEY_[A-Z0-9_]+. If a config sets both, the Anthropic key is the one that pays, and the one osa validate reports.
Error: API key test failed (401 Unauthorized)¶
Symptom:
Causes: - API key is invalid or expired - Wrong key format - Key revoked in the Anthropic Console
Solution:
-
Verify key format:
-
Check the key in the Anthropic Console:
- Visit https://platform.claude.com/settings/keys
- Verify key exists and is active
-
Check that the workspace it belongs to has not hit a spend limit
-
Generate new key if needed:
- Go to https://platform.claude.com/settings/keys
- Create new API key
-
Update environment variable
-
Test directly:
curl https://api.anthropic.com/v1/models \ -H "x-api-key: $ANTHROPIC_API_KEY_MYPROJECT" \ -H "anthropic-version: 2023-06-01" # Should return 200 OK with model listA community key is used against Anthropic's own API rather than the platform's endpoint on AWS, because it is not authorized on the platform's workspace. That is the endpoint
--test-api-keyprobes too, so the curl above and the validator agree.For an OpenRouter community key, the equivalent is:
Error: API key test failed (403 Forbidden)¶
Symptom:
Cause: API key doesn't have necessary permissions, or the account has no funds left.
Solution:
- Check the account balance:
- Visit https://platform.claude.com/settings/billing
- Ensure the account has credit available
-
For an OpenRouter community key, check https://openrouter.ai/credits instead
-
Check key permissions:
- A key scoped to one workspace cannot spend from another
-
Verify the key has access to the models you want to use
-
Add funds:
- Top up the account, or raise the workspace spend limit
- Test again afterwards
Runtime Errors¶
Error: CORS policy blocked¶
Browser Console:
Access to fetch at 'https://api.osc.earth/osa/...' from origin 'https://mysite.com'
has been blocked by CORS policy
Cause: Your website origin not listed in cors_origins config.
Solution:
-
Add your origin to config:
-
Redeploy assistant (config changes require restart)
-
Verify origin exactly matches:
Common Issues: - Forgot www subdomain variant - http:// vs https:// mismatch - Port number missing (e.g., :3000) - Trailing slash in config (remove it)
This is not a Content Security Policy (CSP) error
A CORS rejection comes from the backend deciding whether to answer your origin, and is fixed in cors_origins as above. A CSP violation comes from your own page blocking the request or script before it is sent, and is fixed in your page's CSP header instead; see Content Security Policy (CSP) in the Widget Deployment Guide. The two look similar in the console but need different fixes.
Error: Widget not loading¶
Symptom: Widget icon doesn't appear or widget doesn't open.
Causes: 1. Script not loaded 2. Wrong community ID 3. API endpoint unreachable 4. JavaScript errors
Diagnosis:
-
Check browser console (F12 -> Console):
-
Verify script loads:
-
Check network tab:
osa-chat-widget.jsshould load (200 OK)- API requests should succeed
Solutions:
Wrong community ID:
<!-- Wrong - ID doesn't match config -->
<script src="https://demo.osc.earth/osa-chat-widget.js"></script>
<script>
OSAChatWidget.setConfig({
communityId: 'wrong-id' // Check this matches config.yaml
});
</script>
<!-- Correct -->
<script src="https://demo.osc.earth/osa-chat-widget.js"></script>
<script>
OSAChatWidget.setConfig({
communityId: 'hed' // Must match config.yaml id field
});
</script>
There is no OSAWidget global and init() takes no arguments; all configuration goes through setConfig().
Script placement:
<!-- Wrong - setConfig() runs before the widget script defines OSAChatWidget -->
<head>
<script>
OSAChatWidget.setConfig({ communityId: 'hed' });
</script>
<script src="https://demo.osc.earth/osa-chat-widget.js"></script>
</head>
<!-- Correct - load the widget script first -->
<body>
<script src="https://demo.osc.earth/osa-chat-widget.js"></script>
<script>
OSAChatWidget.setConfig({ communityId: 'hed' });
</script>
</body>
The <script src="...osa-chat-widget.js"> tag must come before the inline setConfig() call, and must never carry defer or async unless paired with data-no-auto-init and a manual OSAChatWidget.init() call afterward; see Loading the Script Asynchronously.
API endpoint:
// Check if the widget's backend is reachable (production)
fetch('https://widget.osc.earth/osa/health')
.then(r => r.json())
.then(console.log);
// Should show: {status: "healthy"}
Error: Messages not getting responses¶
Symptom: Widget accepts input but shows loading spinner indefinitely.
Causes: 1. API key not configured 2. Network errors 3. Model timeout 4. Backend server down
Diagnosis:
- Check browser network tab:
- Look for failed API requests
- Check response status codes
-
Look for timeout errors
-
Check API health: The widget's own traffic goes through
https://widget.osc.earth/osa(the Cloudflare Worker proxy in front of the backend), so check that host first, not the backend it sits in front of:https://api.osc.earth/osa/healthreaches the FastAPI backend behind the worker directly, which is useful too, but a widget-specific issue (CORS, rate limiting, Turnstile) shows up atwidget.osc.earth, not atapi.osc.earth. -
Check backend logs (if you have access):
Solutions:
API key missing: - Verify anthropic_api_key_env_var is set on server, or openrouter_api_key_env_var for a community funded through OpenRouter - Check env var exists: echo $ANTHROPIC_API_KEY_XXX - Restart server after adding env var
Network errors: - Check firewall rules - Verify API endpoint accessible - Check DNS resolution
Timeouts: - May indicate model is slow or overloaded - Try claude-haiku-4-5, which is the faster of the two Claude models, or lower reasoning_effort (see below) - Check status.anthropic.com, or OpenRouter's status page for an OpenRouter community
Deployment Issues¶
Error: Config file not found¶
Symptom:
Cause: Config file not in expected location or path incorrect.
Solution:
-
Check file exists:
-
Verify directory structure:
-
Check file name:
- Must be exactly
config.yaml - Lowercase, not
Config.yaml
Error: Assistant not discovered¶
Symptom: After deployment, osa myproject ask "test" returns:
Cause: Assistant not registered in registry.
Diagnosis:
-
Check discovery:
-
Check directory structure:
Solution:
-
Ensure config.yaml exists:
-
Restart server:
-
Check for validation errors:
Testing Issues¶
Error: Tests fail with import errors¶
Symptom:
Cause: Module not in Python path or not installed.
Solution:
-
Sync dependencies:
-
Run tests from repo root:
-
Check Python path:
Error: Tests fail with fixture errors¶
Symptom:
Cause: Using old pytest version or fixture not available.
Solution:
-
Update pytest:
-
Verify pytest version:
Performance Issues¶
Issue: Widget loads slowly¶
Symptoms: - Widget takes 3-5+ seconds to appear - First message slow to respond
Causes: 1. Large system prompt (too many preloaded docs) 2. Slow model 3. Network latency 4. Cold start (server sleeping)
Solutions:
Reduce preloaded docs:
# Before - 5 preloaded docs = slow
documentation:
- title: Doc 1
preload: true
- title: Doc 2
preload: true
# ... 3 more preloaded
# After - 1-2 critical docs only
documentation:
- title: Core Spec
preload: true
- title: API Ref
preload: false # Fetch on-demand
Use the faster model:
# Before - Sonnet 5.5 is the more capable of the two Claude models, and the slower
default_model: claude-sonnet-5-5
# After - Haiku 4.5, the platform default
default_model: claude-haiku-4-5
Think less:
# Every model with reasoning levels runs at high unless told otherwise
reasoning_effort: medium # or low
Thinking costs latency before the first token, and every offered model runs at high by default. Lowering reasoning_effort is often a better first step than changing the model: on one NWB question GPT-6 Luna's median time to first text was about 5 seconds at high, 11 at xhigh and 48 at max. Haiku's level is a thinking budget (1,024, 2,048 or 4,096 tokens) and Sonnet decides per request, so a thinking-heavy question is slower on either than a lookup is. See reasoning_effort.
Check network:
# Test latency of the host the widget actually talks to
time curl https://widget.osc.earth/osa/health
# Should be < 1 second; https://api.osc.earth/osa is the FastAPI
# backend behind this worker, useful for isolating worker vs. backend latency
Issue: High API costs¶
Symptoms: - AWS Marketplace bill higher than expected - Usage exceeded budget
Causes: 1. claude-sonnet-5-5 where claude-haiku-4-5 would do 2. A high reasoning_effort (thinking tokens are billed as output, and every model runs at high unless set) 3. Long conversations (context accumulation) 4. Many users 5. Preloaded docs increasing prompt size 6. Prompt caching disabled, so the same system prompt is billed at full rate on every turn
Solutions:
Use the cheaper model:
# Sonnet 5.5: twice Haiku's rate, worth it for genuinely hard questions
default_model: claude-sonnet-5-5
# Haiku 4.5: the default, and enough for documentation Q&A
default_model: claude-haiku-4-5
# GPT-6 Luna on Amazon Bedrock: about a ninth of Haiku's input rate
default_model: openai.gpt-6-luna
Think less:
Reduce preloaded docs: - Each preloaded doc adds to every request - Move to on-demand retrieval - Keep preloaded docs minimal
Keep prompt caching on: - Cache reads bill at a tenth of the input rate, and the system prompt is the largest repeated part of a request - A cache write costs more than an uncached read once, then pays for itself on the second turn
Monitor usage: - GET /{community_id}/metrics reports total_estimated_cost from the same pricing table the platform bills against (admin or community key required) - Set up budget alerts in AWS - Track usage by community ID
Cost Comparison: | Model | Input (per 1M tokens) | Output (per 1M tokens) | Use Case | |-------|----------------------|------------------------|----------| | claude-haiku-4-5 | $1.00 | $5.00 | General Q&A, FAQ generation | | claude-sonnet-5-5 | $2.00 | $10.00 | Complex reasoning, long threads | | openai.gpt-6-luna | $0.11 | $0.55 | Documentation Q&A (Amazon Bedrock) | | qwen.qwen3-next-80b-a3b | $0.14 | $1.20 | Documentation Q&A (Amazon Bedrock) | | openai.gpt-oss-120b | $0.15 | $0.60 | Documentation Q&A (Amazon Bedrock) |
Opus is not offered here. Every offered model is priced at or below Sonnet 5.5, and the three Bedrock models at or below Haiku 4.5, so a community's cost is predictable and the fallback is always the cheaper one.
Widget Integration Issues¶
Issue: Widget appears but can't read page content¶
Symptom: Assistant says "I cannot access the current page content" when asked about page.
Cause: enable_page_context disabled or tool not available.
Solution:
Verify:
# Check config
grep enable_page_context src/assistants/myproject/config.yaml
# Should show: enable_page_context: true
Issue: Widget positioning problems¶
Symptom: Widget icon overlaps with page content or appears in wrong location.
Cause: CSS conflicts with your site's styles.
Solution:
Add custom CSS:
<style>
/* Adjust widget position */
.osa-chat-widget {
bottom: 20px !important;
right: 20px !important;
z-index: 9999 !important;
}
</style>
Check for conflicts:
Documentation Sync Issues¶
Error: Documentation fetch fails¶
Symptom: Assistant says "I couldn't retrieve that documentation."
Causes: 1. source_url unreachable 2. GitHub rate limit 3. URL changed/moved
Diagnosis:
# Test URL directly
curl -I https://raw.githubusercontent.com/org/repo/main/docs.md
# Should return 200 OK
Solutions:
URL moved:
# Update to new URL
documentation:
- title: My Doc
url: https://newsite.org/docs
source_url: https://raw.githubusercontent.com/org/repo/main/docs/newpath.md
GitHub rate limit: - Wait an hour for limit reset - Use GitHub token for higher limits - Move docs to CDN
HTTPS required:
# Wrong - HTTP not secure
source_url: http://example.com/docs.md
# Correct - HTTPS
source_url: https://example.com/docs.md
Getting Help¶
If you're still stuck after trying these solutions:
-
Check logs:
-
Run health check:
-
Validate config again:
-
File an issue:
- GitHub: https://github.com/OpenScience-Collective/osa/issues
-
Include:
- Error message (full text)
- Config file (sanitized, remove API keys!)
- Steps to reproduce
- Environment (OS, Python version)
-
Ask in discussions:
- https://github.com/OpenScience-Collective/osa/discussions
Prevention Checklist¶
Before deploying to production:
- Config validated locally (
osa validate) - API key tested (
--test-api-key) - CORS origins match production domains
- Documentation URLs verified (returns 200 OK)
- Widget tested on actual website
- Costs estimated based on expected usage
- Monitoring/alerts configured
- Team trained on troubleshooting basics
Common Error Messages Reference¶
Quick lookup table:
| Error | Section | Quick Fix |
|---|---|---|
| YAML syntax error | Config Validation | Check indentation, quotes |
| kebab-case | Config Validation | Use lowercase with hyphens |
| Invalid CORS origin | Config Validation | Add https:// prefix |
| preload requires source_url | Config Validation | Add source_url field |
| API key not set | API Keys | Export env var |
| 401 Unauthorized | API Keys | Check API key validity |
| CORS blocked | Runtime | Add origin to config |
| Widget not loading | Runtime | Check script, community ID |
| Config not found | Deployment | Check file path |
| Assistant not discovered | Deployment | Restart server |