{"record":{"id":"8ceda6e1172b479e","repo":"iflytek/astron-agent","slug":"response-failed-assemble-requestheader-error","errorCode":"RESPONSE_FAILED","errorMessage":"assemble requestHeader  error:","messagePattern":"assemble requestHeader  error:","errorType":"exception","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/extra/CoreSystemService.java","lineNumber":358,"sourceCode":"                    append(method).append(\" \").append(path).append(\" HTTP/1.1\").append(\"\\n\").append(\"digest: \").append(digest);\n            Charset charset = Charset.forName(\"UTF-8\");\n\n            // Use hmac-sha256 to calculate signature\n            Mac mac = Mac.getInstance(\"hmacsha256\");\n            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), \"hmacsha256\");\n            mac.init(spec);\n            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));\n            String sha = Base64.getEncoder().encodeToString(hexDigits);\n            // Build header\n            String authorization = String.format(\"hmac-auth api_key=\\\"%s\\\", algorithm=\\\"%s\\\", headers=\\\"%s\\\", signature=\\\"%s\\\"\", apiKey, \"hmac-sha256\", \"host date request-line digest\", sha);\n            Map<String, String> header = new HashMap<String, String>();\n            header.put(\"authorization\", authorization);\n            header.put(\"host\", host);\n            header.put(\"date\", date);\n            header.put(\"digest\", digest);\n            return header;\n        } catch (Exception e) {\n            throw new BusinessException(ResponseEnum.RESPONSE_FAILED, \"assemble requestHeader  error:\" + e.getMessage());\n        }\n    }\n\n    /**\n     * Adds workflow comparison data for protocol validation Saves comparison protocols for the\n     * specified workflow and version\n     *\n     * @param protocol The flow protocol containing comparison data\n     * @param flowId The workflow ID to add comparisons for\n     * @param version The specific version of the workflow\n     * @throws BusinessException if the add operation fails\n     */\n    public void addComparisons(FlowProtocol protocol, String flowId, String version) {\n        String url = apiUrl.getWorkflow().concat(ADD_COMPARISONS_PATH);\n        JSONObject jsonObject = new JSONObject()\n                .fluentPut(\"flow_id\", flowId)\n                .fluentPut(\"version\", version)\n                .fluentPut(\"data\", protocol);","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/extra/CoreSystemService.java#L340-L376","documentation":"Thrown by CoreSystemService.assembleRequestHeader when building the signed request headers (authorization, host, date, digest) for calls to the core system API fails. Any exception in the signing/assembly path (HMAC/digest computation, date formatting, host/secret configuration) is wrapped as BusinessException(RESPONSE_FAILED) with message 'assemble requestHeader  error:' + the cause.","triggerScenarios":"publish, auth, uploadFile, or batchUploadFile invokes assembleRequestHeader and the digest/signature computation throws — null API secret, bad key/secret charset, unsupported digest algorithm, or null host/url parts.","commonSituations":"Missing or malformed API key/secret in configuration; host or URL not set so signing input is null; JVM lacking the digest algorithm; misconfigured character encoding for the secret bytes.","solutions":["Read the embedded cause in the message ('assemble requestHeader  error: ...') to identify the failing signing step.","Verify the API key, secret, and host used by CoreSystemService are configured and non-null.","Confirm the request URL/host is fully formed before header assembly (no null path or query).","Unit-test assembleRequestHeader directly with the current config to reproduce the digest failure in isolation."],"exampleFix":"// before\nMac mac = Mac.getInstance(\"HmacSHA256\");\nmac.init(new SecretKeySpec(secret.getBytes(), \"HmacSHA256\"));\n// after\nif (apiKey == null || secret == null || host == null) {\n    throw new BusinessException(ResponseEnum.RESPONSE_FAILED, \"missing apiKey/secret/host for header signing\");\n}\nMac mac = Mac.getInstance(\"HmacSHA256\");\nmac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), \"HmacSHA256\"));","handlingStrategy":"validation","validationCode":"// before assembling headers\nboolean canSign(String apiKey, String secret, String host) {\n    return apiKey != null && !apiKey.isBlank()\n        && secret != null && !secret.isBlank()\n        && host != null && !host.isBlank();\n}","typeGuard":"boolean hasSigningMaterial(Map<String, String> config) {\n    return Stream.of(\"apiKey\", \"apiSecret\", \"host\").allMatch(k -> {\n        String v = config.get(k);\n        return v != null && !v.isBlank();\n    });\n}","tryCatchPattern":"try {\n    Map<String, String> header = coreSystemService.assembleRequestHeader(url, body);\n} catch (BusinessException e) {\n    // message contains 'assemble requestHeader  error:' + cause\n    log.error(\"header signing failed: {}\", e.getMessage());\n}","preventionTips":["Check apiKey/secret/host configuration at service startup, not per-request.","Use explicit charset (UTF-8) for secret bytes to avoid platform-dependent failures.","Unit-test header assembly whenever the signing algorithm or config schema changes.","Keep the digest algorithm name in a validated constant."],"tags":["http","request-signing","authentication","headers"],"backgroundTag":"http-request-failed","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}