showcase/shell-docs/src/content/docs/frontends/angular/guides/troubleshooting.mdx
Use this page for failures in the Angular application layer. Runtime and protocol diagnostics remain available in the shared troubleshooting pages, so you can investigate the complete request without switching frontend docs.
Confirm that the browser is calling the same Copilot Runtime URL your server actually exposes:
import { provideCopilotKit } from "@copilotkit/angular";
export const appConfig = {
providers: [
provideCopilotKit({
runtimeUrl: "/api/copilotkit",
}),
],
};
Then inspect GET {runtimeUrl}/info. A healthy response lists the expected
agent ids. If the request fails:
127.0.0.1 when local localhost resolution is unreliable.The CopilotKit service exposes
runtimeConnectionStatus, runtimeUrl, and the resolved agents as signals.
Use them in a temporary diagnostic component:
import { Component, inject } from "@angular/core";
import { CopilotKit } from "@copilotkit/angular";
@Component({
selector: "app-copilot-diagnostics",
standalone: true,
template: `
<p>Runtime: {{ copilotKit.runtimeConnectionStatus() }}</p>
<p>Agents: {{ agentIds().join(", ") || "none" }}</p>
`,
})
export class CopilotDiagnosticsComponent {
protected readonly copilotKit = inject(CopilotKit);
protected readonly agentIds = () =>
Object.keys(this.copilotKit.agents());
}
Remove diagnostics that expose topology or identifiers before production.
injectAgentStore("support") and <copilot-chat agentId="support" /> must use
an id returned by the runtime or registered through agents or
selfManagedAgents. After the runtime finishes connecting,
injectAgentStore throws an error that includes the requested id and known
agents when no match exists.
If you intend to use the default agent, either register an agent named
default or pass the real id explicitly everywhere the chat, state, tools, or
interrupt controller selects an agent.
Registrations are injector-scoped. Call registerFrontendTool,
registerRenderToolCall, or registerHumanInTheLoop from a field initializer,
constructor, provider factory, or another active injection context.
Check these in order:
agentId matches the chat's agent.For a source-backed registration, see Frontend tools and generative UI.
Use listError() for user-visible thread-list and mutation failures. The
broader error() signal can also contain developer configuration errors such
as a missing runtime URL or unavailable thread endpoints.
Mutation methods return promises. Handle rejection and confirm before permanent deletion:
await threads.renameThread(threadId, nextName).catch((error) => {
console.error("Thread rename failed", error);
});
See injectThreads for loading,
pagination, realtime, and optimistic-mutation behavior.
Read injectInterrupt().error() after a failed predicate, handler, or resume.
Expired decisions use InterruptExpiredError. Resolve or cancel every pending
interrupt id when the backend emits multiple simultaneous decisions.
The controller clears stale decisions when a thread changes or a new run starts. Do not cache it outside the injector that created it.
afterNextRender.The complete contract is in Angular production and lifecycle.