{"record":{"id":"574fed9f2e943c1f","repo":"arduino/Arduino","slug":"unexpected-s-response-header-s","errorCode":null,"errorMessage":"Unexpected %s response header: %s","messagePattern":"Unexpected (.+?) response header: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"arduino-core/src/processing/app/i18n/python/requests/packages/urllib3/contrib/ntlmpool.py","lineNumber":83,"sourceCode":"        conn.request('GET', self.authurl, None, headers)\n        res = conn.getresponse()\n        reshdr = dict(res.getheaders())\n        log.debug('Response status: %s %s' % (res.status, res.reason))\n        log.debug('Response headers: %s' % reshdr)\n        log.debug('Response data: %s [...]' % res.read(100))\n\n        # Remove the reference to the socket, so that it can not be closed by\n        # the response object (we want to keep the socket open)\n        res.fp = None\n\n        # Server should respond with a challenge message\n        auth_header_values = reshdr[resp_header].split(', ')\n        auth_header_value = None\n        for s in auth_header_values:\n            if s[:5] == 'NTLM ':\n                auth_header_value = s[5:]\n        if auth_header_value is None:\n            raise Exception('Unexpected %s response header: %s' %\n                            (resp_header, reshdr[resp_header]))\n\n        # Send authentication message\n        ServerChallenge, NegotiateFlags = \\\n            ntlm.parse_NTLM_CHALLENGE_MESSAGE(auth_header_value)\n        auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge,\n                                                         self.user,\n                                                         self.domain,\n                                                         self.pw,\n                                                         NegotiateFlags)\n        headers[req_header] = 'NTLM %s' % auth_msg\n        log.debug('Request headers: %s' % headers)\n        conn.request('GET', self.authurl, None, headers)\n        res = conn.getresponse()\n        log.debug('Response status: %s %s' % (res.status, res.reason))\n        log.debug('Response headers: %s' % dict(res.getheaders()))\n        log.debug('Response data: %s [...]' % res.read()[:100])\n        if res.status != 200:","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/arduino/Arduino/blob/a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee/arduino-core/src/processing/app/i18n/python/requests/packages/urllib3/contrib/ntlmpool.py#L65-L101","documentation":"The NTLM connection pool wraps urllib3's connection creation in an NTLM handshake: on connect it sends the negotiate header and then scans the WWW-Authenticate response header for a token starting with 'NTLM ' to extract the server challenge. If the response header contains no such NTLM token, _new_conn raises this generic Exception because the server did not reply with the NTLM challenge the handshake requires.","triggerScenarios":"Creating an NTLMConnectionPool and issuing a request when the server's WWW-Authenticate response does not include a 'NTLM <base64>' token — e.g. the server only offers Negotiate/Basic auth, sends a malformed header, or the pool is pointed at a non-NTLM endpoint.","commonSituations":"Pointing NTLMConnectionPool at a proxy or IIS server configured for Kerberos/Negotiate only; header mangled by a proxy that strips WWW-Authenticate; connecting to a plain HTTP service that does not speak NTLM at all.","solutions":["Inspect the raw WWW-Authenticate header returned by the server (curl -v or res.getheaders()) and confirm whether NTLM is offered.","If the server only offers Negotiate/Kerberos, use a Kerberos-capable client (e.g. requests-kerberos) instead of NTLMConnectionPool, or enable NTLM on the server/proxy.","Check for intermediaries (proxies, load balancers) stripping or rewriting WWW-Authenticate and whitelist the NTLM header.","If only Basic auth is available, use a normal urllib3/requests pool with HTTPBasicAuth instead of the NTLM pool."],"exampleFix":"// before\npool = NTLMConnectionPool(host='proxy.corp', username=user, password=pwd)  # server only does Negotiate\n// after\nimport requests\nresp = requests.get('http://proxy.corp/path', auth=(user, pwd))  # or configure NTLM on the proxy","handlingStrategy":"validation","validationCode":"def server_offers_ntlm(host, port=80, path='/'):\n    import http.client\n    conn = http.client.HTTPConnection(host, port)\n    conn.request('GET', path)\n    hdr = conn.getresponse().getheader('WWW-Authenticate', '')\n    return 'NTLM' in hdr","typeGuard":"def is_ntlm_challenge(www_authenticate_value):\n    return isinstance(www_authenticate_value, str) and 'NTLM ' in www_authenticate_value","tryCatchPattern":"try:\n    conn = ntlm_pool._new_conn()\nexcept Exception as e:\n    if 'Unexpected' in str(e) and 'response header' in str(e):\n        log.error('Server did not answer with an NTLM challenge: %s', e)\n        # fall back to basic auth or a plain pool\n    else:\n        raise","preventionTips":["Probe WWW-Authenticate on the target before wiring up NTLMConnectionPool.","Confirm proxy/load balancers preserve the WWW-Authenticate header.","Enable NTLM (or use Negotiate with a Kerberos client) on servers that only offer Kerberos.","Keep ntlm/ python-ntlm dependencies installed — a missing parse module can also break the exchange."],"tags":["python","ntlm","http-auth","proxy"],"backgroundTag":"unexpected-http-status","analyzedSha":"a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee","analyzedAt":"2026-09-06T10:13:38.901Z","contentChangedAt":"2026-09-06T10:13:38.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}