lobehub/lobehub · error · Error

Failed to unpublish agent group: ${response.statusText}

Error message

Failed to unpublish agent group: ${response.statusText}

What it means

Inner throw in `unpublishAgentGroup` (agentGroup.ts:823) when POST `${MARKET_BASE_URL}/api/v1/agent-groups/:identifier/unpublish` returns non-2xx. Gated by `agentGroupWriteProcedure`. Message embeds upstream `statusText` and is preserved by the outer catch.

Source

Thrown at apps/server/src/routers/lambda/market/agentGroup.ts:823

        if (!headers['x-lobe-trust-token'] && accessToken) {
          headers['Authorization'] = `Bearer ${accessToken}`;
        }

        const response = await fetch(unpublishUrl, {
          headers,
          method: 'POST',
        });

        if (!response.ok) {
          const errorText = await response.text();
          log(
            'Unpublish agent group failed: %s %s - %s',
            response.status,
            response.statusText,
            errorText,
          );
          throw new Error(`Failed to unpublish agent group: ${response.statusText}`);
        }

        log('Unpublish agent group success');
        return { success: true };
      } catch (error) {
        log('Error unpublishing agent group: %O', error);
        throw new TRPCError({
          cause: error,
          code: 'INTERNAL_SERVER_ERROR',
          message: error instanceof Error ? error.message : 'Failed to unpublish agent group',
        });
      }
    }),
});

export type AgentGroupRouter = typeof agentGroupRouter;

View on GitHub (pinned to 10f24d7ade)

Solutions

  1. Decode embedded `statusText`: 'Not Found' → already gone (treat as success on the client), 'Forbidden' → ownership, 'Unauthorized' → auth.
  2. Guard the UI with `checkOwnership` before showing unpublish.
  3. Make the unpublish call idempotent on the frontend: 404 = already unpublished, return success.
  4. curl `MARKET_BASE_URL/api/v1/agent-groups/<id>/unpublish` with the bearer token to confirm auth vs ownership.

Example fix

// before
throw new Error(`Failed to unpublish agent group: ${response.statusText}`);
// after — treat already-unpublished (404) as success, surface others
if (response.status === 404) return { success: true, alreadyUnpublished: true };
throw new Error(`Failed to unpublish agent group (${response.status}): ${errorText || response.statusText}`);
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm ownership before allowing unpublish
const ownership = await trpc.market.agentGroup.checkOwnership.query({ identifier });
if (!ownership.isOwner) throw new Error('Only the owner can unpublish');

Type guard

function isUnpublishResult(v: unknown): v is { success: boolean } {
  const r = v as Record<string, unknown>;
  return !!r && r.success === true;
}

Try / catch

try {
  await trpc.market.agentGroup.unpublishAgentGroup.mutate({ identifier });
} catch (e) {
  const msg = (e as Error)?.message ?? '';
  if (/not found/i.test(msg)) return; // already unpublished — treat as success
  if (/forbidden/i.test(msg)) { /* not owner */ }
  else throw e;
}

Prevention

When it happens

Trigger: Market returns 403 because the caller is not the owner of `identifier`; 404 because the identifier doesn't exist (already unpublished or never published); 401 from missing/invalid auth headers; 5xx during Market unpublish pipeline.

Common situations: UI lets a non-owner see the unpublish button; double-click unpublish where the second call finds the group already unpublished; user session expired between page load and click.

Related errors


AI-assisted analysis of lobehub/lobehub@10f24d7ade (2026-08-12). Data as JSON: /api/errors/224e6e7f14bc2e6a. Report an issue: GitHub.