{"record":{"id":"7354662598d1713b","repo":"GopeedLab/gopeed","slug":"unsupported-ed2k-link-type","errorCode":null,"errorMessage":"unsupported ed2k link type","messagePattern":"unsupported ed2k link type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/protocol/ed2k/fetcher.go","lineNumber":409,"sourceCode":"\nfunc (fm *FetcherManager) Close() error {\n\tfm.mu.Lock()\n\tdefer fm.mu.Unlock()\n\n\tif fm.client != nil {\n\t\tfm.client.Close()\n\t\tfm.client = nil\n\t}\n\treturn nil\n}\n\nfunc parseLink(raw string) (goed2k.EMuleLink, error) {\n\tlink, err := goed2k.ParseEMuleLink(raw)\n\tif err != nil {\n\t\treturn goed2k.EMuleLink{}, err\n\t}\n\tif link.Type != goed2k.LinkFile {\n\t\treturn goed2k.EMuleLink{}, errors.New(\"unsupported ed2k link type\")\n\t}\n\treturn link, nil\n}\n\nfunc buildResource(link goed2k.EMuleLink) *base.Resource {\n\treturn &base.Resource{\n\t\tSize:  link.NumberValue,\n\t\tRange: false,\n\t\tHash:  link.Hash.String(),\n\t\tFiles: []*base.FileInfo{\n\t\t\t{\n\t\t\t\tName: link.StringValue,\n\t\t\t\tSize: link.NumberValue,\n\t\t\t},\n\t\t},\n\t}\n}\n","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/internal/protocol/ed2k/fetcher.go#L391-L427","documentation":"parseLink (internal/protocol/ed2k/fetcher.go:402-412) parses the string with goed2k.ParseEMuleLink successfully, but the link's Type is not goed2k.LinkFile. The eMule link scheme covers more than files — server links (ed2k://|server|ip|port|/) and server-list links are valid links that this downloader cannot fetch, so they are rejected explicitly.","triggerScenarios":"Creating/resolving a task with an ed2k server link (ed2k://|server|207.62.153.10|4242|/) or server-list link instead of a file link; paste/clipboard bugs that grab the wrong link from a page of mixed ed2k links; parsing the 'file' variant with malformed segments such that goed2k still classifies it as a non-file type.","commonSituations":"Users pasting a server link copied from an eMule server list; indexers that return multiple ed2k link kinds; scripts iterating over ed2k:// URLs scraped from a page without filtering by the |file| segment.","solutions":["Use only file links: ed2k://|file|<name>|<size>|<md4-hex>|/","Filter candidate links before task creation: require the segment after ed2k://| to be 'file'","Surface a clear 'not a downloadable ed2k file link' message in UI instead of retrying","Check link.StringValue/NumberValue exist after parse if you need extra safety"],"exampleFix":"// before\n_, err := downloader.Resolve(&base.Request{URL: \"ed2k://|server|10.0.0.1|4661|/\"}, nil)\n\n// after\nisFile := func(u string) bool { return strings.HasPrefix(u, \"ed2k://|file|\") }\nif !isFile(u) { return errors.New(\"only ed2k file links are supported\") }\n_, err := downloader.Resolve(&base.Request{URL: u}, nil)","handlingStrategy":"validation","validationCode":"func isEd2kFileLink(u string) bool {\n    return strings.HasPrefix(strings.ToLower(u), \"ed2k://|file|\")\n}\nif !isEd2kFileLink(u) { return fmt.Errorf(\"unsupported ed2k link (need |file|): %s\", u) }\n_, err := downloader.Resolve(&base.Request{URL: u}, nil)","typeGuard":"func isEd2kFileLink(u string) bool { return strings.HasPrefix(strings.ToLower(u), \"ed2k://|file|\") }","tryCatchPattern":"if _, err := downloader.Resolve(req, nil); err != nil {\n    if strings.Contains(err.Error(), \"unsupported ed2k link type\") {\n        // tell the user only ed2k file links are downloadable; filter the input\n    }\n}","preventionTips":["Filter scraped/pasted ed2k links to the |file| variant before task creation","Validate links client-side (prefix check) for a friendlier message","Remember server and server-list links parse fine but are never fetchable here"],"tags":["ed2k","url","validation","unsupported-type"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}