{"record":{"id":"0cd2dc1176721bbf","repo":"TryGhost/Ghost","slug":"failed-to-fetch-recommendations","errorCode":null,"errorMessage":"Failed to fetch recommendations","messagePattern":"Failed to fetch recommendations","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/portal/src/utils/api.js","lineNumber":133,"sourceCode":"                } else {\n                    throw new Error('Failed to fetch offer data');\n                }\n            });\n        },\n\n        recommendations({limit = 100} = {limit: 100}) {\n            const url = contentEndpointFor({resource: 'recommendations', params: {limit}});\n            return makeRequest({\n                url,\n                method: 'GET',\n                headers: {\n                    'Content-Type': 'application/json'\n                }\n            }).then(function (res) {\n                if (res.ok) {\n                    return res.json();\n                } else {\n                    throw new Error('Failed to fetch recommendations');\n                }\n            });\n        }\n    };\n\n    api.feedback = {\n        async add({uuid, key, postId, score}) {\n            let url = endpointFor({type: 'members', resource: 'feedback'});\n            if (uuid && key) { // only necessary if not logged in, and both are required if so\n                url = url + `?uuid=${uuid}&key=${key}`;\n            }\n            const body = {\n                feedback: [\n                    {\n                        post_id: postId,\n                        score\n                    }\n                ]","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/apps/portal/src/utils/api.js#L115-L151","documentation":"Thrown in api.site.recommendations() when GET {apiUrl}/recommendations/?limit=... returns non-ok. Message 'Failed to fetch recommendations'. Portal uses recommendations to render the recommended-sites UI.","triggerScenarios":"Portal loads the recommendations content endpoint; non-ok response — no recommendations configured, invalid API key, endpoint not present in older Ghost.","commonSituations":"Older Ghost version that predates the recommendations content endpoint; rotated/stale Content API key; CORS / apiUrl misconfiguration; recommendations feature disabled in labs on the server.","solutions":["Verify the Ghost server version exposes /api/content/recommendations/.","Check the Content API key in the Portal data attributes.","Confirm apiUrl and CORS allow the page origin.","If unused, consider not rendering the recommendations block to avoid the call entirely."],"exampleFix":"// before\nthrow new Error('Failed to fetch recommendations');\n\n// after\nthrow new Error(`Failed to fetch recommendations (${res.status} ${res.statusText})`);","handlingStrategy":"fallback","validationCode":"// skip the call entirely when recommendations are not shown\nfunction shouldFetchRecommendations(state) {\n    return state.features?.recommendations && state.showRecommendations;\n}","typeGuard":null,"tryCatchPattern":"try {\n    return await api.site.recommendations();\n} catch (err) {\n    // non-critical — render empty recommendations\n    return [];\n}","preventionTips":["Only fetch recommendations when the UI actually renders them.","Degrade gracefully — recommendations are non-critical.","Confirm Ghost server version exposes the recommendations content endpoint.","Keep the Content API key current."],"tags":["portal","recommendations","content-api","network"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}