{"record":{"id":"01f5dbf04dd9d598","repo":"Mintplex-Labs/anything-llm","slug":"failed-to-fetch-documents-by-paths","errorCode":null,"errorMessage":"Failed to fetch documents by paths.","messagePattern":"Failed to fetch documents by paths\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/src/models/system.js","lineNumber":114,"sourceCode":"    return await fetch(\n      `${API_BASE}/system/local-files/search?q=${encodeURIComponent(query)}`,\n      { headers: baseHeaders() }\n    )\n      .then((res) => {\n        if (!res.ok) throw new Error(\"Search failed.\");\n        return res.json();\n      })\n      .then((res) => res.results)\n      .catch(() => []);\n  },\n  getDocumentsByDocPaths: async function (docpaths = []) {\n    return await fetch(`${API_BASE}/system/local-files/by-docpaths`, {\n      method: \"POST\",\n      headers: baseHeaders(),\n      body: JSON.stringify({ docpaths }),\n    })\n      .then((res) => {\n        if (!res.ok) throw new Error(\"Failed to fetch documents by paths.\");\n        return res.json();\n      })\n      .then((res) => res.documents)\n      .catch(() => []);\n  },\n  needsAuthCheck: function () {\n    const lastAuthCheck = window.localStorage.getItem(AUTH_TIMESTAMP);\n    if (!lastAuthCheck) return true;\n    const expiresAtMs = Number(lastAuthCheck) + 60 * 5 * 1000; // expires in 5 minutes in ms\n    return Number(new Date()) > expiresAtMs;\n  },\n\n  checkAuth: async function (currentToken = null) {\n    const valid = await fetch(`${API_BASE}/system/check-token`, {\n      headers: baseHeaders(currentToken),\n    })\n      .then((res) => res.ok)\n      .catch(() => false);","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/frontend/src/models/system.js#L96-L132","documentation":"Thrown by System.getDocumentsByDocPaths on a non-2xx POST to /api/system/local-files/by-docpaths with body {docpaths}. Unlike the GET listing/search routes, this is a POST batch lookup keyed by document paths. The .catch() returns an empty array, masking server errors as 'no documents found'.","triggerScenarios":"Calling getDocumentsByDocPaths([\"doc-a\",\"doc-b\"]) when one or more paths do not resolve (the server may 4xx/5xx the whole batch), when docpaths is empty and the server rejects it, or when the auth token is rejected.","commonSituations":"Passing stale docpaths after documents were deleted/renamed; sending a very large array that exceeds a body-size limit on a reverse proxy; mixing paths from different workspaces.","solutions":["Trim docpaths to known-good entries from a prior localFiles listing call.","Check the POST body size is under your proxy's max body size (e.g. client_max_body_size).","Read the response body in DevTools for which path the server rejected.","Confirm baseHeaders() sends a valid token."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function validDocpaths(paths) {\n  return Array.isArray(paths) && paths.every(p => typeof p === \"string\" && p.length > 0) && paths.length <= 500;\n}","typeGuard":"/** @param {any} r @returns {r is Array} */\nfunction isDocsArray(r) { return Array.isArray(r); }","tryCatchPattern":"const docs = await System.getDocumentsByDocPaths(paths);\nif (!isDocsArray(docs)) { /* server error — not 'no docs' */ }","preventionTips":["Cap the batch size to stay under proxy body limits.","Filter out empty/non-string paths before sending.","Do not treat an empty array result as definitive without a status check."],"tags":["network","documents","batch","auth"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}