{"record":{"id":"c2d168a40da72a1b","repo":"apache/hadoop","slug":"proxy-error-s-or-s-set-without-the-other","errorCode":null,"errorMessage":"Proxy error: %s or %s set without the other.","messagePattern":"Proxy error: (.+?) or (.+?) set without the other\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/DefaultOBSClientFactory.java","lineNumber":197,"sourceCode":"        LOG.warn(\"Proxy host set without port. Using HTTP default \"\n            + OBSConstants.DEFAULT_HTTP_PORT);\n        obsConf.getHttpProxy()\n            .setProxyPort(OBSConstants.DEFAULT_HTTP_PORT);\n      }\n    }\n    String proxyUsername = conf.getTrimmed(OBSConstants.PROXY_USERNAME);\n    String proxyPassword = null;\n    char[] proxyPass = conf.getPassword(OBSConstants.PROXY_PASSWORD);\n    if (proxyPass != null) {\n      proxyPassword = new String(proxyPass).trim();\n    }\n    if ((proxyUsername == null) != (proxyPassword == null)) {\n      String msg =\n          \"Proxy error: \" + OBSConstants.PROXY_USERNAME + \" or \"\n              + OBSConstants.PROXY_PASSWORD\n              + \" set without the other.\";\n      LOG.error(msg);\n      throw new IllegalArgumentException(msg);\n    }\n    obsConf.setHttpProxy(proxyHost, proxyPort, proxyUsername,\n        proxyPassword);\n    if (LOG.isDebugEnabled()) {\n      LOG.debug(\n          \"Using proxy server {}:{} as user {} on \"\n              + \"domain {} as workstation {}\",\n          obsConf.getHttpProxy().getProxyAddr(),\n          obsConf.getHttpProxy().getProxyPort(),\n          obsConf.getHttpProxy().getProxyUName(),\n          obsConf.getHttpProxy().getDomain(),\n          obsConf.getHttpProxy().getWorkstation());\n    }\n  }\n\n  /**\n   * Creates an {@link ObsClient} from the established configuration.\n   *","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/DefaultOBSClientFactory.java#L179-L215","documentation":"DefaultOBSClientFactory reads fs.obs.proxy.username (getTrimmed) and fs.obs.proxy.password (getPassword) when setting up the HTTP proxy for the OBS client. If exactly one of the two is configured (XOR check), initialization aborts with IllegalArgumentException 'Proxy error: fs.obs.proxy.username or fs.obs.proxy.password set without the other.' The OBS SDK requires both credentials together, so a half-configured proxy is rejected before any connection is attempted.","triggerScenarios":"Setting fs.obs.proxy.username in core-site.xml (or a job config) without fs.obs.proxy.password; providing the password only via a credential provider that fails to resolve (getPassword returns null → password side missing); trailing-whitespace/empty username trimmed to null; per-bucket config override (fs.obs.bucket.X.proxy.username) that forgets the matching password key.","commonSituations":"Adding proxy settings incrementally during corporate-network onboarding; copy-pasting an example config that only shows the username line; password moved to a JCEKS credential provider that is not on hadoop.security.credential.provider.path, so getPassword() yields null; typos in one of the two key names.","solutions":["Set BOTH fs.obs.proxy.username and fs.obs.proxy.password (or remove both to disable authenticated proxy).","If the password comes from a credential provider, verify the entry exists: hadoop credential list -provider jceks://... and confirm the provider path config resolves in the same context (same user/classpath).","Check for typos: keys are exactly fs.obs.proxy.username / fs.obs.proxy.password; per-bucket variants must mirror each other.","If the proxy truly needs no auth, clear both keys and rely on fs.obs.proxy.host + fs.obs.proxy.port only."],"exampleFix":"# before (core-site.xml)\n<property><name>fs.obs.proxy.host</name><value>proxy.corp</value></property>\n<property><name>fs.obs.proxy.port</name><value>8080</value></property>\n<property><name>fs.obs.proxy.username</name><value>obsuser</value></property>\n<!-- password missing -->\n\n# after\n<property><name>fs.obs.proxy.username</name><value>obsuser</value></property>\n<property><name>fs.obs.proxy.password</name><value>obs-pass</value></property>\n<!-- or store via: hadoop credential create fs.obs.proxy.password -value xxx -provider localjceks://...</property -->","handlingStrategy":"validation","validationCode":"static boolean proxyConfigConsistent(Configuration conf) {\n  String u = conf.getTrimmed(\"fs.obs.proxy.username\");\n  char[] p = conf.getPassword(\"fs.obs.proxy.password\");\n  return (u == null) == (p == null); // both set or both unset\n}\nif (!proxyConfigConsistent(conf)) throw new ConfigException(\"set both fs.obs.proxy.username and fs.obs.proxy.password\");","typeGuard":null,"tryCatchPattern":"try {\n  obsFs.initialize(uri, conf);\n} catch (IllegalArgumentException e) {\n  if (String.valueOf(e.getMessage()).contains(\"fs.obs.proxy.username\")) {\n  \tif (String.valueOf(e.getMessage()).contains(\"Proxy error\")) {\n      throw new ConfigException(\"Proxy credentials half-configured\", e);\n    }\n  }\n  throw e;\n}","preventionTips":["Config-lint all paired keys (host/port/user/password) at deploy time.","Prefer credential-provider entries for proxy passwords; verify with hadoop credential list.","Per-bucket overrides must mirror base keys: if you override username, override password too."],"tags":["obs","huaweicloud","proxy","config","initialization"],"backgroundTag":"missing-config-value","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}