{"record":{"id":"c6c6a2ecfa2dc841","repo":"postalserver/postal","slug":"error-when-scanning-with-rspamd-got-response-co","errorCode":null,"errorMessage":"Error when scanning with rspamd (got #{response.code})","messagePattern":"Error when scanning with rspamd \\(got #(.+?)\\)","errorType":"exception","errorClass":"Postal::MessageInspectors::Rspamd::Error","httpStatus":null,"severity":"warning","filePath":"lib/postal/message_inspectors/rspamd.rb","lineNumber":68,"sourceCode":"          # still trigger rspamd to treat this as an outbound email\n          # and disable certain checks.\n          # https://rspamd.com/doc/tutorials/scanning_outbound.html\n          request[\"Ip\"] = \"\"\n        end\n\n        response = nil\n        begin\n          response = http.request(request)\n        rescue StandardError => e\n          logger.error \"Error talking to rspamd: #{e.class} (#{e.message})\"\n          logger.error e.backtrace[0, 5]\n\n          raise Error, \"Error when scanning with rspamd (#{e.class})\"\n        end\n\n        unless response.is_a?(Net::HTTPOK)\n          logger.info \"Got #{response.code} status from rspamd, wanted 200\"\n          raise Error, \"Error when scanning with rspamd (got #{response.code})\"\n        end\n\n        response\n      end\n\n    end\n  end\nend\n","sourceCodeStart":50,"sourceCodeEnd":77,"githubUrl":"https://github.com/postalserver/postal/blob/d038eaa8c763d3cafa797ccd6f773d53470bd336/lib/postal/message_inspectors/rspamd.rb#L50-L77","documentation":"The rspamd inspector requires an HTTP 200 from /checkv2; any other status (401 invalid Password header, 403 forbidden, 413 oversized message, 500 rspamd internal error) is logged ('Got <code> status from rspamd, wanted 200') and raised as Rspamd::Error with the code interpolated. As with the transport error, inspect_message catches it and records a SpamCheck named ERROR, so mail proceeds without spam results.","triggerScenarios":"Scanning a message when the configured rspamd password does not match rspamd's own controller password (401); a message larger than rspamd's max-size (413/502 depending on version); rspamd returning 500 because of broken symbol/map configuration; requesting flags rspamd rejects.","commonSituations":"Password rotated on one side only (postal.yml vs rspamd's .env/controller config); large attachments tripping rspamd limits; rspamd upgraded with changed map/symbol syntax causing internal errors; a proxy in front of rspamd answering with its own error codes.","solutions":["Align the password: message_inspectors.rspamd.password in postal.yml must equal rspamd's controller password, then restart both","Check rspamd's own logs at the timestamp to see why it returned the non-200 code","If 413/size-related, raise rspamd max_size or inspect before attachment-heavy traffic","After a rspamd upgrade, run rspamd configtest and fix broken symbols/maps that cause 500s","Confirm the port really is the controller (/checkv2 endpoint), not another rspamd worker port that returns 405/404"],"exampleFix":"# before (postal.yml)\nmessage_inspectors:\n  rspamd:\n    host: rspamd\n    port: 11334\n    ssl: true\n    password: old-secret   # -> 'Got 401 status from rspamd'\n\n# after\nmessage_inspectors:\n  rspamd:\n    host: rspamd\n    port: 11334\n    ssl: true\n    password: <%= ENV[\"RSPAMD_PASSWORD\"] %>  # same value rspamd starts with","handlingStrategy":"validation","validationCode":"# verify credentials/config against rspamd before relying on scanning\nrequire \"net/http\"\nhttp = Net::HTTP.new(config.host, config.port)\nhttp.use_ssl = true if config.ssl\nreq = Net::HTTP::Get.new(\"/ping\")\nreq[\"Password\"] = config.password if config.password\nresponse = http.request(req)\nraise ArgumentError, \"rspamd auth/config invalid: #{response.code}\" unless response.code.to_i == 200","typeGuard":"def rspamd_config_valid?(config)\n  # cheap authenticated probe: /ping must return 200 with the same headers /checkv2 uses\n  response = rspamd_request(config, Net::HTTP::Get.new(\"/ping\"))\n  response.is_a?(Net::HTTPOK)\nrescue StandardError\n  false\nend","tryCatchPattern":"begin\n  inspector.inspect_message(inspection)\nrescue Postal::MessageInspectors::Rspamd::Error => e\n  if e.message.include?(\"got \")\n    # HTTP-level rejection (auth/size/config): fix config; retrying the same message rarely helps\n  end\nend","preventionTips":["Manage the rspamd password as a single shared secret consumed by both postal.yml and rspamd's config","Alert on any SpamCheck named 'ERROR' with 'got <code>' text - it means non-200 responses are ongoing","After rspamd upgrades run its config test so /checkv2 does not start returning 500s","Check rspamd's max-size against your largest expected message before it produces 413s"],"tags":["postal","rspamd","spam","http-status","authentication"],"backgroundTag":"upstream-http-error","analyzedSha":"d038eaa8c763d3cafa797ccd6f773d53470bd336","analyzedAt":"2026-08-21T13:52:57.446Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}