microsoft/aspire · error · AspireError
$error
Error message
$error
What it means
invoke_capability() raises AspireError(result['$error']) when the AppHost returns a structured error response for the capability call. The literal '$error' in the message is the response key inspected here; the raised AspireError carries the server-side error code and message. Type-mismatch errors are converted to a formatted type error instead via _format_type_error.
Solutions
- Read the raised AspireError's code/message to identify the server-side cause.
- Verify the capability_id matches one advertised by the AppHost (list capabilities or check generated stubs).
- Fix argument types to match the capability schema; use the generated wrapper methods where available.
- Regenerate the Python module if the AppHost version changed and capabilities were renamed.
Example fix
// before
result = client.invoke_capability("add_resoruce", {"name": 123})
// after
result = client.invoke_capability("add_resource", {"name": "cache"}) Defensive patterns
Strategy: try-catch
Validate before calling
def assert_capability(client, capability_id, capabilities):
if capability_id not in capabilities:
raise ValueError(f'unknown capability {capability_id!r}') Try / catch
try:
result = client.invoke_capability(capability_id, args)
except AspireError as e:
log.error('capability %s failed: %s (%s)', capability_id, e.message, getattr(e, 'code', None))
raise Prevention
- Use generated wrapper methods instead of raw invoke_capability where available
- Validate capability ids against the advertised list
- Keep argument types aligned with the capability schema; regenerate stubs after AppHost updates
When it happens
Trigger: Calling client.invoke_capability(capability_id, args) where the server rejects the call: unknown capability id, invalid/mistyped arguments, or any capability-level failure surfaced through the $error field.
Common situations: Typos in capability_id; passing Python values the server cannot unmarshal (wrong types, unsupported fields); calling a capability removed or renamed after an AppHost/SDK update; server-side validation rejecting the argument dict.
Related errors
- result.$error
- -32000
- Request was cancelled
- Already connected to AppHost backchannel.
- An input name is required when uploading a file.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/d80b1462822f75f8.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.Python/PythonModuleBuilder.cs:1150
self,
capability_id: str,
args: dict[str, typing.Any] | None = None,
kwargs: typing.Mapping[str, typing.Any] | None = None
) -> typing.Any:
'''
Invoke an ATS capability by ID.
Capabilities are operations exposed by [AspireExport] attributes.
Results are automatically wrapped in Handle objects when applicable.
'''
self._check_connection()
result = self._send_request("invokeCapability", capability_id, self._marshal_transport_value(args or {}))
# Check for structured error response
if _is_ats_error(result):
if result["$error"].get("code") == AtsErrorCodes.TYPE_MISMATCH:
raise _format_type_error(result["$error"])
raise AspireError(result["$error"])
# Wrap handles automatically
return _wrap_if_handle(result, self, kwargs)
def _marshal_transport_value(self, value: typing.Any) -> typing.Any:
if callable(value):
return self.register_callback(value)
if isinstance(value, dict):
return {key: self._marshal_transport_value(nested_value) for key, nested_value in value.items()}
if isinstance(value, (list, tuple)):
return [self._marshal_transport_value(item) for item in value]
return value
def _send_request(self, method: str, *params: typing.Any) -> typing.Any:
'''Send a JSON-RPC request and wait for response'''
with self._lock:
self._request_id += 1
request_id = self._request_idView on GitHub (pinned to 25830f84bd)