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
- Decode embedded `statusText`: 'Not Found' → already gone (treat as success on the client), 'Forbidden' → ownership, 'Unauthorized' → auth.
- Guard the UI with `checkOwnership` before showing unpublish.
- Make the unpublish call idempotent on the frontend: 404 = already unpublished, return success.
- 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
- Gate the unpublish button on checkOwnership.isOwner.
- Make the unpublish action idempotent on the client (404 = success).
- Disable the button on first click to prevent double-submits.
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
- Failed to publish agent group: ${response.statusText}
- Failed to get agent group forks: ${response.statusText}
- Failed to get agent group list: ${response.statusText}
- INTERNAL_SERVER_ERROR
- INTERNAL_SERVER_ERROR
AI-assisted analysis of lobehub/lobehub@10f24d7ade (2026-08-12).
Data as JSON: /api/errors/224e6e7f14bc2e6a.
Report an issue: GitHub.