{"record":{"id":"224e6e7f14bc2e6a","repo":"lobehub/lobehub","slug":"failed-to-unpublish-agent-group-response-status","errorCode":null,"errorMessage":"Failed to unpublish agent group: ${response.statusText}","messagePattern":"Failed to unpublish agent group: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/server/src/routers/lambda/market/agentGroup.ts","lineNumber":823,"sourceCode":"\n        if (!headers['x-lobe-trust-token'] && accessToken) {\n          headers['Authorization'] = `Bearer ${accessToken}`;\n        }\n\n        const response = await fetch(unpublishUrl, {\n          headers,\n          method: 'POST',\n        });\n\n        if (!response.ok) {\n          const errorText = await response.text();\n          log(\n            'Unpublish agent group failed: %s %s - %s',\n            response.status,\n            response.statusText,\n            errorText,\n          );\n          throw new Error(`Failed to unpublish agent group: ${response.statusText}`);\n        }\n\n        log('Unpublish agent group success');\n        return { success: true };\n      } catch (error) {\n        log('Error unpublishing agent group: %O', error);\n        throw new TRPCError({\n          cause: error,\n          code: 'INTERNAL_SERVER_ERROR',\n          message: error instanceof Error ? error.message : 'Failed to unpublish agent group',\n        });\n      }\n    }),\n});\n\nexport type AgentGroupRouter = typeof agentGroupRouter;\n","sourceCodeStart":805,"sourceCodeEnd":840,"githubUrl":"https://github.com/lobehub/lobehub/blob/10f24d7ade75139093a9373b364f6bc91f3cd7db/apps/server/src/routers/lambda/market/agentGroup.ts#L805-L840","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nthrow new Error(`Failed to unpublish agent group: ${response.statusText}`);\n// after — treat already-unpublished (404) as success, surface others\nif (response.status === 404) return { success: true, alreadyUnpublished: true };\nthrow new Error(`Failed to unpublish agent group (${response.status}): ${errorText || response.statusText}`);","handlingStrategy":"try-catch","validationCode":"// Confirm ownership before allowing unpublish\nconst ownership = await trpc.market.agentGroup.checkOwnership.query({ identifier });\nif (!ownership.isOwner) throw new Error('Only the owner can unpublish');","typeGuard":"function isUnpublishResult(v: unknown): v is { success: boolean } {\n  const r = v as Record<string, unknown>;\n  return !!r && r.success === true;\n}","tryCatchPattern":"try {\n  await trpc.market.agentGroup.unpublishAgentGroup.mutate({ identifier });\n} catch (e) {\n  const msg = (e as Error)?.message ?? '';\n  if (/not found/i.test(msg)) return; // already unpublished — treat as success\n  if (/forbidden/i.test(msg)) { /* not owner */ }\n  else throw e;\n}","preventionTips":["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."],"tags":["trpc","market-api","fetch","write-op","permissions","auth"],"backgroundTag":null,"analyzedSha":"10f24d7ade75139093a9373b364f6bc91f3cd7db","analyzedAt":"2026-08-12T11:43:19.543Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}