{"record":{"id":"bc88577b9b4dabbb","repo":"gethomepage/homepage","slug":"duplicati-request-failed-for-endpoint","errorCode":null,"errorMessage":"Duplicati request failed for ${endpoint}","messagePattern":"Duplicati request failed for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/widgets/duplicati/proxy.js","lineNumber":83,"sourceCode":"  const body = asJson(data);\n  if (!body?.AccessToken) {\n    throw new Error(\"Duplicati login response did not include an access token\");\n  }\n\n  return body.AccessToken;\n}\n\nasync function apiGet(widget, endpoint, accessToken) {\n  const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));\n  const [status, , data] = await httpProxy(url, {\n    method: \"GET\",\n    headers: {\n      Authorization: `Bearer ${accessToken}`,\n    },\n  });\n\n  if (status !== 200) {\n    throw new Error(`Duplicati request failed for ${endpoint}`);\n  }\n\n  return asJson(data);\n}\n\nexport default async function duplicatiProxyHandler(req, res) {\n  const { group, service, index } = req.query;\n  const widget = await getServiceWidget(group, service, index);\n\n  if (!widget) {\n    return res.status(400).json({ error: \"Invalid proxy service type\" });\n  }\n\n  if (!widget.url || !widget.password) {\n    return res.status(500).json({\n      error: {\n        message: `Duplicati widget is missing required url and password`,\n      },","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/gethomepage/homepage/blob/b6dca1ae033e613d8e692f9a161a3cc53a5a2857/src/widgets/duplicati/proxy.js#L65-L101","documentation":"Thrown by apiGet() in the Duplicati proxy when an authenticated GET to a Duplicati API endpoint returns a non-200 status. This fires after a successful login, so the token is valid but the specific data endpoint still rejected the request.","triggerScenarios":"The AccessToken used for the call is valid but the requested endpoint path is wrong (404), the token expired between login and this call (401), Duplicati returns 500 for a specific backup task, or the endpoint name passed in the widget does not exist on this Duplicati version.","commonSituations":"Endpoint parameter in the widget config mis-spelled or not supported by the installed Duplicati version; clock skew causing immediate token expiry; Duplicati mid-backup returning 500 for status endpoints; reverse proxy rate-limiting returning 429.","solutions":["Check the Homepage debug log for the status code tied to the failing endpoint to distinguish 404 (wrong path) from 401 (token) from 500 (server).","Confirm the endpoint name matches Duplicati's API for the installed version.","If intermittent, treat 500/429 as transient and verify Duplicati health / proxy rate limits.","Re-check that login (which produced the token) used the same base URL as this GET so the token is scoped correctly.","If 401, review whether the token TTL is shorter than the polling interval and whether login should be re-run per request."],"exampleFix":"// before\nif (status !== 200) {\n  throw new Error(`Duplicati request failed for ${endpoint}`);\n}\n// after\nif (status !== 200) {\n  throw new Error(`Duplicati GET ${endpoint} failed (HTTP ${status}): ${Buffer.from(data).toString().slice(0, 200)}`);\n}","handlingStrategy":"retry","validationCode":"// Validate the endpoint against the Duplicati API surface before calling.\nconst DUPLICATI_ENDPOINTS = new Set([\"backup\",\"state\",\"progress\",\"serverstate\"]);\nfunction isValidDuplicatiEndpoint(ep) {\n  return typeof ep === \"string\" && DUPLICATI_ENDPOINTS.has(ep.toLowerCase());\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await apiGet(widget, endpoint, accessToken);\n} catch (err) {\n  if (/request failed for/.test(err.message) && isTransient) {\n    // Re-login once, then retry the GET a single time.\n    const token = await login(widget);\n    return await apiGet(widget, endpoint, token);\n  }\n  throw err;\n}","preventionTips":["Treat 500/429 as transient with one bounded retry after re-login.","Log the status code separately from the endpoint name to speed diagnosis.","Confirm the endpoint set is supported by the installed Duplicati version."],"tags":["network","duplicati","http-proxy","authentication","widget"],"backgroundTag":null,"analyzedSha":"b6dca1ae033e613d8e692f9a161a3cc53a5a2857","analyzedAt":"2026-08-13T04:48:44.121Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}