{"id":"48c63c6fba32d6cd","repo":"sindresorhus/got","slug":"unexpected-end-of-link-header-parameters-rawlin","errorCode":null,"errorMessage":"Unexpected end of Link header parameters: ${rawLinkParameters.join(';')}","messagePattern":"Unexpected end of Link header parameters: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"source/core/parse-link-header.ts","lineNumber":81,"sourceCode":"\tfor (const item of items) {\n\t\t// https://tools.ietf.org/html/rfc5988#section-5\n\t\tconst [rawUriReference, ...rawLinkParameters] = splitHeaderValue(item, ';') as [string, ...string[]];\n\t\tconst trimmedUriReference = rawUriReference.trim();\n\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with\n\t\tif (trimmedUriReference[0] !== '<' || trimmedUriReference.at(-1) !== '>') {\n\t\t\tthrow new Error(`Invalid format of the Link header reference: ${trimmedUriReference}`);\n\t\t}\n\n\t\tconst reference = trimmedUriReference.slice(1, -1);\n\t\tconst parameters: Record<string, string> = {};\n\n\t\tif (reference.includes('<') || reference.includes('>')) {\n\t\t\tthrow new Error(`Invalid format of the Link header reference: ${trimmedUriReference}`);\n\t\t}\n\n\t\tif (rawLinkParameters.length === 0) {\n\t\t\tthrow new Error(`Unexpected end of Link header parameters: ${rawLinkParameters.join(';')}`);\n\t\t}\n\n\t\tfor (const rawParameter of rawLinkParameters) {\n\t\t\tconst trimmedRawParameter = rawParameter.trim();\n\t\t\tconst center = trimmedRawParameter.indexOf('=');\n\n\t\t\tif (center === -1) {\n\t\t\t\tthrow new Error(`Failed to parse Link header: ${link}`);\n\t\t\t}\n\n\t\t\tconst name = trimmedRawParameter.slice(0, center).trim();\n\t\t\tconst value = trimmedRawParameter.slice(center + 1).trim();\n\n\t\t\tparameters[name] = value;\n\t\t}\n\n\t\tparsed.push({\n\t\t\treference,","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/parse-link-header.ts#L63-L99","documentation":"parse-link-header.ts:81: after extracting the `<reference>`, the parser expects at least one `;`-separated parameter (e.g. `rel=\"next\"`). A bare `</path>` with no parameters violates RFC 8288 (a link without `rel` is meaningless) and Got refuses it rather than emitting a parameter-less entry.","triggerScenarios":"A `Link` header entry like `</page2>` with no trailing `; rel=...`. Triggered when iterating items in `parseLinkHeader`: `rawLinkParameters` is empty so the join is empty and the message reads `Unexpected end of Link header parameters:`.","commonSituations":"A server emitting only the URL portion of a link (typo or partial template); a debugging endpoint hand-crafting headers; truncation by a proxy that strips everything after the first `;`.","solutions":["Ensure every `Link` entry includes at least a `rel` parameter, e.g. `</page2>; rel=\"next\"`.","If you control the server, validate emitted Link headers against RFC 8288 in tests.","If the upstream is unfixable, disable Got's automatic link pagination for that endpoint.","Log `response.headers.link` to confirm which entry is missing parameters."],"exampleFix":"// before: upstream sends  Link: </page2>\n\n// after: upstream sends   Link: </page2>; rel=\"next\"","handlingStrategy":"validation","validationCode":"function hasParameters(item) {\n  return item.split(';').length > 1;\n}\nconst ok = (response.headers.link ?? '').split(',').every(hasParameters);","typeGuard":"const linkItemHasParams = (s: string): boolean => s.split(';').length > 1;","tryCatchPattern":null,"preventionTips":["Ensure server-side Link entries always include `rel`.","Validate emitted Link headers in server unit tests.","Disable link pagination for endpoints that emit bare references.","Log the raw Link header on parse failure."],"tags":["link-header","parsing","pagination","rfc-8288"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}