Bug Report: apply_template silently skips built-in extensions — all 11 templates affected
Severity: High
Category: Infra
Platform: All
Confidence: Confirmed
Description
POST /api/templates/{id}/apply silently skips any built-in extension that is not currently healthy. The response reports results[svc_id] = "skipped: Extension not installed: X" and restart_required: false with enabled_count: 0, which looks like a successful apply to the frontend even though nothing was enabled.
Affected File(s)
dream-server/extensions/services/dashboard-api/routers/templates.py — apply_template(), _BASE_COMPOSE_SERVICES
dream-server/extensions/services/dashboard-api/routers/extensions.py — _activate_service()
Root Cause
_activate_service(service_id) resolves ext_dir = USER_EXTENSIONS_DIR / service_id. Built-in extensions (n8n, litellm, langfuse, tts, whisper, openclaw, perplexica, searxng, privacy-shield, token-spy, comfyui) live in EXTENSIONS_DIR, not USER_EXTENSIONS_DIR. The check ext_dir.is_dir() returns False, raising HTTPException(404, "Extension not installed: n8n").
apply_template wraps the call in try/except HTTPException and records the result as "skipped: Extension not installed: n8n" — no user-visible error.
The comment in templates.py says _activate_service checks both user-installed and built-in extension dirs, but this is incorrect. The code only checks USER_EXTENSIONS_DIR.
_BASE_COMPOSE_SERVICES = frozenset({"llama-server", "open-webui", "dashboard", "dashboard-api"}) — correctly excludes always-running services but does not include other built-in extensions (n8n, litellm, etc.).
Evidence
# extensions.py:977
def _activate_service(service_id: str) -> dict:
ext_dir = (USER_EXTENSIONS_DIR / service_id).resolve() # ← only USER_EXTENSIONS_DIR
if not ext_dir.is_dir():
raise HTTPException(status_code=404, detail=f"Extension not installed: {service_id}")
Compare with _is_dep_enabled() at line 936, which correctly checks both dirs:
if (EXTENSIONS_DIR / dep / "compose.yaml").exists(): # ← correctly checks EXTENSIONS_DIR
return True
if (USER_EXTENSIONS_DIR / dep / "compose.yaml").exists():
return True
Services silently skipped per template
| Template |
Built-in services silently skipped if not healthy |
| ai-coding-workspace |
n8n, openclaw |
| chat-playground |
tts, whisper |
| creative-studio |
comfyui, tts, whisper |
| developer-homelab |
n8n, token-spy |
| llm-platform |
litellm, langfuse, token-spy, n8n |
| ml-data-workshop |
litellm, langfuse, n8n |
| multi-agent-laboratory |
openclaw, langfuse, n8n |
| no-code-ai-builder |
n8n |
| personal-knowledge-base |
perplexica, searxng, whisper |
| private-research-hub |
searxng, perplexica, privacy-shield |
| voice-assistant |
whisper, tts, n8n |
All 11 templates are affected.
Platform Analysis
All platforms. The template system is a dashboard-api feature with no platform-specific branching.
Reproduction
- Have a DreamServer install where n8n is not running (or disable it: rename
extensions/services/n8n/compose.yaml → compose.yaml.disabled)
POST /api/templates/no-code-ai-builder/apply with valid API key
- Response shows
"n8n": "skipped: Extension not installed: n8n" and enabled_count: 0
- UI shows "Template applied" but n8n is not running
Impact
The template system's primary purpose — setting up groups of services with one click — is broken for built-in services that are not currently running. All 11 templates fail silently for a majority of their listed services on systems where those services aren't already healthy.
Suggested Approach
Add a built-in extension activation path in apply_template that checks EXTENSIONS_DIR / svc_id / "compose.yaml.disabled" and renames it to compose.yaml (same mechanism _activate_service uses for USER_EXTENSIONS_DIR). Mirror the pattern from _is_dep_enabled() which already correctly checks both directories.
Filed by automated infra auditor after full-sweep of changes merged 2026-04-06 → 2026-04-11 on upstream/main @ c0600ca.
Bug Report: apply_template silently skips built-in extensions — all 11 templates affected
Severity: High
Category: Infra
Platform: All
Confidence: Confirmed
Description
POST /api/templates/{id}/applysilently skips any built-in extension that is not currently healthy. The response reportsresults[svc_id] = "skipped: Extension not installed: X"andrestart_required: falsewithenabled_count: 0, which looks like a successful apply to the frontend even though nothing was enabled.Affected File(s)
dream-server/extensions/services/dashboard-api/routers/templates.py—apply_template(),_BASE_COMPOSE_SERVICESdream-server/extensions/services/dashboard-api/routers/extensions.py—_activate_service()Root Cause
_activate_service(service_id)resolvesext_dir = USER_EXTENSIONS_DIR / service_id. Built-in extensions (n8n, litellm, langfuse, tts, whisper, openclaw, perplexica, searxng, privacy-shield, token-spy, comfyui) live inEXTENSIONS_DIR, notUSER_EXTENSIONS_DIR. The checkext_dir.is_dir()returnsFalse, raisingHTTPException(404, "Extension not installed: n8n").apply_templatewraps the call intry/except HTTPExceptionand records the result as"skipped: Extension not installed: n8n"— no user-visible error.The comment in
templates.pysays_activate_service checks both user-installed and built-in extension dirs, but this is incorrect. The code only checksUSER_EXTENSIONS_DIR._BASE_COMPOSE_SERVICES = frozenset({"llama-server", "open-webui", "dashboard", "dashboard-api"})— correctly excludes always-running services but does not include other built-in extensions (n8n, litellm, etc.).Evidence
Compare with
_is_dep_enabled()at line 936, which correctly checks both dirs:Services silently skipped per template
All 11 templates are affected.
Platform Analysis
All platforms. The template system is a dashboard-api feature with no platform-specific branching.
Reproduction
extensions/services/n8n/compose.yaml→compose.yaml.disabled)POST /api/templates/no-code-ai-builder/applywith valid API key"n8n": "skipped: Extension not installed: n8n"andenabled_count: 0Impact
The template system's primary purpose — setting up groups of services with one click — is broken for built-in services that are not currently running. All 11 templates fail silently for a majority of their listed services on systems where those services aren't already healthy.
Suggested Approach
Add a built-in extension activation path in
apply_templatethat checksEXTENSIONS_DIR / svc_id / "compose.yaml.disabled"and renames it tocompose.yaml(same mechanism_activate_serviceuses forUSER_EXTENSIONS_DIR). Mirror the pattern from_is_dep_enabled()which already correctly checks both directories.Filed by automated infra auditor after full-sweep of changes merged 2026-04-06 → 2026-04-11 on upstream/main @ c0600ca.