{"record":{"id":"c889c103d690e5a6","repo":"jordansissel/fpm","slug":"metacpan-release-query-failed","errorCode":null,"errorMessage":"metacpan release query failed","messagePattern":"metacpan release query failed","errorType":"validation","errorClass":"FPM::InvalidPackageConfiguration","httpStatus":null,"severity":"error","filePath":"lib/fpm/package/cpan.rb","lineNumber":342,"sourceCode":"                 :distribution => distribution,\n                 :version => cpan_version)\n\n    # default to latest version unless we specify one\n    if cpan_version.nil?\n      self.version = \"#{metadata[\"version\"]}\"\n    else\n      self.version = \"#{cpan_version}\"\n    end\n\n    # Search metacpan to get download URL for this version of the module\n    metacpan_search_url = \"#{attributes[:cpan_metacpan_api_url]}/v1/release/_search?_source=download_url\"\n    metacpan_search_query = {\"query\":{\"term\":{\"name\": \"#{distribution}-#{self.version}\" } } }.to_json\n    begin\n      search_response = httppost(metacpan_search_url,metacpan_search_query)\n    rescue Net::HTTPServerException => e\n      logger.error(\"metacpan release query failed.\", :error => e.message,\n                    :url => metacpan_search_url)\n      raise FPM::InvalidPackageConfiguration, \"metacpan release query failed\"\n    end\n\n    data = search_response.body\n    release_metadata = JSON.parse(data)\n\n    download_url = release_metadata['hits']['hits'][0]['_source']['download_url']\n    download_path = URI.parse(download_url).path\n    tarball = File.basename(download_path)\n\n    url_base = \"http://www.cpan.org/\"\n    url_base = \"#{attributes[:cpan_mirror]}\" if !attributes[:cpan_mirror].nil?\n\n    url = \"#{url_base}#{download_path}\"\n    logger.debug(\"Fetching perl module\", :url => url)\n\n    begin\n      response = httpfetch(url)\n    rescue Net::HTTPServerException => e","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/jordansissel/fpm/blob/b6d77ba72a560b687723376a0e5115c3a92634ad/lib/fpm/package/cpan.rb#L324-L360","documentation":"While resolving a Perl module to a downloadable tarball, fpm POSTs an Elasticsearch-style query to the metacpan API at /v1/release/_search to get the download_url for Distribution-VERSION. If the HTTP layer raises Net::HTTPServerException (any 4xx response), fpm logs the underlying error and re-raises FPM::InvalidPackageConfiguration with this message.","triggerScenarios":"Calling fpm -s cpan (input/download path) when metacpan answers 4xx to the release _search POST: 404 from an outdated/changed API base URL (--cpan-metacpan-api-url pointing at a wrong or proxied host), 400 for a malformed query, or a corporate proxy returning 403/407. Only HTTP 4xx raises here; DNS failures and connection refused raise different errors.","commonSituations":"Custom --cpan-metacpan-api-url typo or stale self-hosted metacpan instance; metacpan API schema/endpoint changes after an upgrade; proxy or captive-portal interception of api.metacpan.org; requests behind flaky networks returning 429.","solutions":["Reproduce the failing request outside fpm: curl -s -X POST 'https://fastapi.metacpan.org/v1/release/_search?_source=download_url' -H 'Content-Type: application/json' -d '{\"query\":{\"term\":{\"name\":\"Foo-1.00\"}}}' and inspect the status code","Check that Distribution-VERSION actually exists on metacpan (search the module on metacpan.org); a wrong --version produces a name term with no release","Verify --cpan-metacpan-api-url; unset it or set it to https://fastapi.metacpan.org","If a proxy is involved, configure correct proxy env vars (http_proxy/https_proxy) so the POST is not rejected with 4xx","Update fpm if you run an old release that uses a retired metacpan endpoint"],"exampleFix":"# before\nfpm -s cpan -t deb Foo --cpan-metacpan-api-url https://metacpan.local   # 404 -> metacpan release query failed\n\n# after\nfpm -s cpan -t deb Foo                          # default URL\nfpm -s cpan -t deb Foo --cpan-metacpan-api-url https://fastapi.metacpan.org","handlingStrategy":"retry","validationCode":"require 'net/http'\nuri = URI('https://fastapi.metacpan.org/v1/release/_search?_source=download_url')\nbegin\n  resp = Net::HTTP.post(uri, { query: { term: { name: 'Foo-1.00' } } }.to_json,\n                        'Content-Type' => 'application/json')\n  abort \"metacpan returned HTTP #{resp.code}\" unless resp.code == '200'\nrescue SocketError => e\n  abort \"cannot resolve metacpan: #{e.message}\"\nend","typeGuard":null,"tryCatchPattern":"require 'net/http'\n\n3.times do |attempt|\n  begin\n    pkg = FPM::Package::CPAN.new\n    pkg.input('Foo')\n    break\n  rescue FPM::InvalidPackageConfiguration => e\n    raise if attempt == 2 || !e.message.include?('metacpan release query failed')\n    sleep(2**attempt)   # metacpan 4xx: back off for 429, recheck URL for 4xx\n    warn \"retry #{attempt + 1}/3 after metacpan error\"\n  end\nend","preventionTips":["Pin CI jobs to the default --cpan-metacpan-api-url unless a self-hosted metacpan is verified healthy","Add a preflight curl/Net::HTTP check on the metacpan endpoint before starting the fpm build","Keep fpm updated so its metacpan query shape tracks the live API"],"tags":["fpm","cpan","metacpan","network","http-4xx","packaging"],"backgroundTag":"http-4xx-client-error","analyzedSha":"b6d77ba72a560b687723376a0e5115c3a92634ad","analyzedAt":"2026-08-21T16:39:02.570Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}