different-ai/openwork · error

${message}

Error message

${message}

What it means

After the raw /skill request, refreshSkills checks result.data; when data is undefined it takes the error from the response payload and rethrows it as an Error. The message is the server/transport error text, or the localized 'failed to load skills' fallback when the payload error is neither an Error nor a string.

Source

Thrown at apps/app/src/react-app/domains/settings/state/extensions-store.ts:1536

    if (root !== skillsRoot) skillsLoaded = false;
    if (!optionsOverride?.force && skillsLoaded) return;
    if (refreshSkillsInFlight) return;

    refreshSkillsInFlight = true;
    refreshSkillsAborted = false;
    try {
      setStateField("skillsStatus", null);
      const rawClient = client as unknown as { _client?: { get: (input: { url: string }) => Promise<unknown> } };
      if (!rawClient._client) throw new Error("OpenCode client unavailable.");
      const result = await rawClient._client.get({ url: "/skill" }) as {
        data?: Array<{ name: string; description: string; location: string }>;
        error?: unknown;
      };
      if (result?.data === undefined) {
        const err = result?.error;
        const message = err instanceof Error ? err.message : typeof err === "string" ? err : t("skills.failed_to_load");
        throw new Error(message);
      }
      if (refreshSkillsAborted) return;
      const next: SkillCard[] = Array.isArray(result.data)
        ? result.data.map((entry) => ({
            name: entry.name,
            description: entry.description,
            path: formatSkillPath(entry.location),
          }))
        : [];
      mutateState((current) => ({
        ...current,
        skills: next,
        skillsStatus: next.length ? null : t("skills.no_skills_found"),
        skillsContextKey: getWorkspaceContextKey(),
      }));
      skillsLoaded = true;
      skillsRoot = root;
    } catch (error) {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Check OpenCode server health/logs for why GET /skill returned an error and fix the server-side cause.
  2. Inspect the thrown message: if it is the generic 'failed to load' fallback, log the raw result.error to recover the real cause.
  3. Retry the refresh — transient server restarts commonly produce this; refreshSkills already clears skillsStatus on entry so a re-run is safe.
  4. Verify auth/workspace state: some servers reject /skill when the session is invalid; re-authenticate.

Example fix

// before
await store.refreshSkills({ force: true });
// after
try {
  await store.refreshSkills({ force: true });
} catch (e) {
  logger.warn('skills refresh failed', e); // message here is result.error text or fallback
  scheduleRetry(() => store.refreshSkills({ force: true }));
}
Defensive patterns

Strategy: try-catch

Type guard

function hasSkillData(r: unknown): r is { data: Array<{ name: string; description: string; location: string }> } {
  return !!r && typeof r === "object" && Array.isArray((r as { data?: unknown }).data);
}

Try / catch

try {
  await store.refreshSkills({ force: true });
} catch (e) {
  const msg = e instanceof Error ? e.message : 'failed to load skills';
  logger.warn('GET /skill failed:', msg); // keep raw result.error for diagnosis
  setSkillsError(msg);
}

Prevention

When it happens

Trigger: The _client.get({url:'/skill'}) call resolves (does not reject) with an object whose data is undefined — e.g. the HTTP response carries { error: ... } from a failing OpenCode server, or error is absent/null so the localized skills.failed_to_load message is thrown.

Common situations: OpenCode server returning an error page/JSON for /skill (server restarting, permission problem); a proxy or cache returning non-standard payloads; SDK wrapping network failures into resolved {error} responses.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/0d23e19182bd1dd9. Report an issue: GitHub.