{"record":{"id":"76d6a9373e4dfd0a","repo":"laurent22/joplin","slug":"delta-link-missing-json-stringify-response","errorCode":null,"errorMessage":"Delta link missing: ${JSON.stringify(response)}","messagePattern":"Delta link missing: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/file-api-driver-onedrive.ts","lineNumber":356,"sourceCode":"\t\t// At OneDrive for Business delta requests can only make at the root of OneDrive.  Not sure but it's possible that\n\t\t// the delta API also returns events for files that are copied outside of the app directory and later deleted or\n\t\t// modified when using OneDrive Personal).\n\n\t\tfor (let i = 0; i < response.value.length; i++) {\n\t\t\tconst v = response.value[i];\n\t\t\tif (v.parentReference.id !== pathId) continue;\n\t\t\titems.push(this.makeItem_(v));\n\t\t}\n\n\t\toutput.items = output.items.concat(items);\n\n\t\tlet nextLink = null;\n\n\t\tif (response['@odata.nextLink']) {\n\t\t\tnextLink = response['@odata.nextLink'];\n\t\t\toutput.hasMore = true;\n\t\t} else {\n\t\t\tif (!response['@odata.deltaLink']) throw new Error(`Delta link missing: ${JSON.stringify(response)}`);\n\t\t\tnextLink = response['@odata.deltaLink'];\n\t\t}\n\n\t\toutput.context = { nextLink: nextLink };\n\n\t\t// https://dev.onedrive.com/items/view_delta.htm\n\t\t// The same item may appear more than once in a delta feed, for various reasons. You should use the last occurrence you see.\n\t\t// So remove any duplicate item from the array.\n\t\tconst temp: ItemStat[] = [];\n\t\tconst seenPaths = [];\n\t\tfor (let i = output.items.length - 1; i >= 0; i--) {\n\t\t\tconst item = output.items[i];\n\t\t\tif (seenPaths.indexOf(item.path) >= 0) continue;\n\t\t\ttemp.splice(0, 0, item);\n\t\t\tseenPaths.push(item.path);\n\t\t}\n\n\t\toutput.items = temp;","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/file-api-driver-onedrive.ts#L338-L374","documentation":"Thrown by the OneDrive driver's delta pagination logic. When the delta response has no @odata.nextLink (more pages coming) it expects an @odata.deltaLink (feed complete, use this token next time). If neither is present the response shape is unexpected and the driver refuses to continue, since proceeding would lose the delta cursor.","triggerScenarios":"Calling delta() on OneDrive where the Graph API response omits both @odata.nextLink and @odata.deltaLink — e.g. malformed/empty response, API version returning a different shape, token expiry causing a truncated response.","commonSituations":"OneDrive Graph API version drift; expired/de auth token producing a non-delta body; throttling response (Retry-After) mis-parsed as a delta; corporate SharePoint endpoint with non-standard behavior; rare backend hiccup returning an empty envelope.","solutions":["Re-authenticate the OneDrive account (re-link the sync target) — expired tokens often produce malformed responses.","Inspect the JSON in the message to see what OneDrive actually returned (error body, throttling JSON, etc.).","Retry after a short delay — transient Graph API anomalies frequently self-correct.","Confirm the app requests the Files.ReadWrite.All scope and the endpoint URL is the standard Graph delta URL."],"exampleFix":"// before\nif (!response['@odata.deltaLink']) throw new Error(`Delta link missing: ${JSON.stringify(response)}`);\n// after - tolerate throttling/error envelopes and retry\nif (!response['@odata.deltaLink'] && !response.error) {\n  throw new Error(`Delta link missing: ${JSON.stringify(response)}`);\n}\nif (response.error) { /* re-auth or back off and retry */ }","handlingStrategy":"retry","validationCode":"// Re-check token validity and endpoint shape before delta.\nif (!tokenValid()) await reauthenticate();\nconst probe = await fetch(deltaUrl, { headers });\nif (!probe.ok || probe.headers.get('content-type')?.includes('text/html')) {\n  throw new Error('OneDrive delta endpoint returned a non-JSON response; check auth/URL.');\n}","typeGuard":"function hasDeltaOrNextLink(response: any): boolean {\n  return !!response && (!!response['@odata.deltaLink'] || !!response['@odata.nextLink']);\n}","tryCatchPattern":"for (const delay of [0, 1000, 5000]) {\n  await sleep(delay);\n  try {\n    const response = await graphDelta();\n    if (hasDeltaOrNextLink(response)) { /* proceed */ break; }\n    if (response?.error) throw new Error('OneDrive error: ' + JSON.stringify(response.error));\n  } catch (e) { if (delay === 5000) throw e; }\n}","preventionTips":["Refresh the OneDrive token proactively before it expires.","Confirm the delta URL is the standard Graph endpoint.","Treat throttling (429) responses separately from delta envelopes.","Log raw responses during sync so non-standard shapes are diagnosable."],"tags":["onedrive","sync","delta","pagination","network"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}