gethomepage/homepage · error · Error
Duplicati request failed for ${endpoint}
Error message
Duplicati request failed for ${endpoint} What it means
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.
Source
Thrown at src/widgets/duplicati/proxy.js:83
const body = asJson(data);
if (!body?.AccessToken) {
throw new Error("Duplicati login response did not include an access token");
}
return body.AccessToken;
}
async function apiGet(widget, endpoint, accessToken) {
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const [status, , data] = await httpProxy(url, {
method: "GET",
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (status !== 200) {
throw new Error(`Duplicati request failed for ${endpoint}`);
}
return asJson(data);
}
export default async function duplicatiProxyHandler(req, res) {
const { group, service, index } = req.query;
const widget = await getServiceWidget(group, service, index);
if (!widget) {
return res.status(400).json({ error: "Invalid proxy service type" });
}
if (!widget.url || !widget.password) {
return res.status(500).json({
error: {
message: `Duplicati widget is missing required url and password`,
},View on GitHub (pinned to b6dca1ae03)
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.
Example fix
// before
if (status !== 200) {
throw new Error(`Duplicati request failed for ${endpoint}`);
}
// after
if (status !== 200) {
throw new Error(`Duplicati GET ${endpoint} failed (HTTP ${status}): ${Buffer.from(data).toString().slice(0, 200)}`);
} Defensive patterns
Strategy: retry
Validate before calling
// Validate the endpoint against the Duplicati API surface before calling.
const DUPLICATI_ENDPOINTS = new Set(["backup","state","progress","serverstate"]);
function isValidDuplicatiEndpoint(ep) {
return typeof ep === "string" && DUPLICATI_ENDPOINTS.has(ep.toLowerCase());
} Try / catch
try {
return await apiGet(widget, endpoint, accessToken);
} catch (err) {
if (/request failed for/.test(err.message) && isTransient) {
// Re-login once, then retry the GET a single time.
const token = await login(widget);
return await apiGet(widget, endpoint, token);
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unable to login to Duplicati (status ${status})
- Error getting data from Audiobookshelf: ${status}. Data: ${d
- Duplicati login response did not include an access token
- TrueNAS authentication failed
- Authorization failure getting data from glances API. Data: $
AI-assisted analysis of gethomepage/homepage@b6dca1ae03 (2026-08-13).
Data as JSON: /api/errors/bc88577b9b4dabbb.
Report an issue: GitHub.