{"record":{"id":"c3d89cf3e63bc76f","repo":"moeru-ai/airi","slug":"failed-to-create-aliyun-nls-token-response-mess","errorCode":null,"errorMessage":"Failed to create Aliyun NLS token: ${response.Message || 'unknown error'}","messagePattern":"Failed to create Aliyun NLS token: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"server/apps/api/src/routes/audio-transcription-stream/session.ts","lineNumber":125,"sourceCode":"    RegionId: credentials.region,\n    SignatureMethod: 'HMAC-SHA1',\n    SignatureNonce: randomUUID(),\n    SignatureVersion: '1.0',\n    Timestamp: aliyunTimestamp(new Date()),\n    Version: '2019-02-28',\n  }\n  const canonicalQuery = canonicalizeQuery(params)\n  const signature = encodeURIComponent(signStringToBase64(createStringToSign('POST', '/', canonicalQuery), credentials.accessKeySecret))\n  const endpoint = nlsMetaEndpointFromRegion(credentials.region).toString().replace(/\\/$/, '')\n  const response = await ofetch<{\n    Token?: { ExpireTime?: number, Id?: string }\n    Message?: string\n  }>(`${endpoint}/?Signature=${signature}&${canonicalQuery}`, { method: 'POST' })\n\n  if (typeof response.Token?.Id === 'string' && typeof response.Token?.ExpireTime === 'number')\n    return { token: response.Token.Id, expiresAt: response.Token.ExpireTime * 1000 }\n\n  throw new Error(`Failed to create Aliyun NLS token: ${response.Message || 'unknown error'}`)\n}\n\nfunction sse(payload: { delta: string, type: 'transcript.text.delta' | 'transcript.text.done' }): Uint8Array {\n  return encoder.encode(`data: ${JSON.stringify(payload)}\\n\\n`)\n}\n\nfunction createClientEvent(credentials: AliyunNlsCredentials, name: 'StartTranscription' | 'StopTranscription', sessionId: string, payload?: AliyunNlsStartPayload) {\n  return JSON.stringify({\n    header: {\n      appkey: credentials.appKey,\n      message_id: randomUUID().replaceAll('-', ''),\n      task_id: sessionId,\n      namespace: 'SpeechTranscriber',\n      name,\n    },\n    payload,\n  })\n}","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/server/apps/api/src/routes/audio-transcription-stream/session.ts#L107-L143","documentation":"Thrown by createAliyunNlsToken() (session.ts:125) after the signed POST to the Aliyun NLS CreateToken endpoint returns a body whose Token.Id is not a string or Token.ExpireTime is not a number. The Aliyun RPC response carries a Message field on failure; the code appends it (or 'unknown error') so the caller sees the provider's reason. This is the only path for credential/signature/region problems with the Aliyun NLS token minting step that precedes every transcription session.","triggerScenarios":"Invalid or disabled Aliyun AccessKeyId/AccessKeySecret; the key lacks permission for the NLS CreateToken action; the signature is wrong because the region, endpoint, or canonical query string is mismatched (e.g. internal vs public region mismatch via nlsMetaEndpointFromRegion); the appKey/NLS project is not enabled for the account; clock skew between the server and Aliyun makes the signed Timestamp invalid.","commonSituations":"Fresh deployment where the Aliyun NLS env vars were not set or were copied from another region; a rotated AccessKey whose secret was not updated in the API's env; using a cn-*-internal region endpoint from outside the VPC; the NLS service was never activated for the Aliyun account; container/system clock drift breaks the signature Timestamp.","solutions":["Decode response.Message: 'InvalidAccessKeyId'/'SignatureDoesNotMatch'/'Forbidden' all point to credentials — verify the AccessKeyId, AccessKeySecret, and that the key is enabled and has NLS permissions.","Confirm credentials.region is one of the supported AliyunNlsRegion values (cn-shanghai / cn-beijing / cn-shenzhen, with or without -internal) and matches where the NLS app/appKey is provisioned — do not mix a public region key with an -internal endpoint or vice versa.","Ensure the NLS service and the specific appKey are activated in the Aliyun console for that region.","Check for clock skew: the signed Timestamp (session.ts:98-99,111) must be within Aliyun's allowed window — sync the host clock (NTP) if the server drifts.","Enable request/response logging of the CreateToken call (status + Message) to capture the provider's exact reason instead of 'unknown error'."],"exampleFix":"// before: signing against the wrong endpoint for the region/keys\nconst endpoint = nlsMetaEndpointFromRegion(credentials.region)\n// credentials.region = 'cn-shanghai-internal' but running outside the VPC\n// -> Failed to create Aliyun NLS token: ...\n\n// after: use a public region when egress is outside Aliyun VPC\nconst credentials = {\n  accessKeyId: process.env.ALIYUN_NLS_ACCESS_KEY_ID,\n  accessKeySecret: process.env.ALIYUN_NLS_ACCESS_KEY_SECRET,\n  appKey: process.env.ALIYUN_NLS_APP_KEY,\n  region: process.env.ALIYUN_NLS_REGION ?? 'cn-shanghai', // not the -internal variant\n}","handlingStrategy":"try-catch","validationCode":"// Fail fast in composition: require the four credential fields before the\n// transcription route ever calls createAliyunNlsToken.\nfunction assertAliyunNlsCredentials(c: Partial<AliyunNlsCredentials> | undefined): asserts c is AliyunNlsCredentials {\n  if (!c?.accessKeyId || !c?.accessKeySecret || !c?.appKey || !c?.region) {\n    throw new Error('Aliyun NLS credentials are not fully configured (accessKeyId/accessKeySecret/appKey/region).')\n  }\n}\n// also: validate region is one of the supported enum values to avoid endpoint mismatch","typeGuard":null,"tryCatchPattern":"// In the route handler, map token-creation failures to a clear 5xx with the\n// provider Message, and surface clock/region hints without leaking the secret.\ntry {\n  token = await createAliyunNlsToken(credentials)\n}\ncatch (error) {\n  const msg = errorMessageFromValue(error)\n  // SignatureDoesNotMatch / InvalidAccessKeyId -> 503 (config), others -> 502\n  const status = /Signature|AccessKey|Forbidden/i.test(msg) ? 503 : 502\n  throw new ApiError(status, 'ALIYUN_NLS_TOKEN_FAILED', msg)\n}","preventionTips":["Validate all four credential fields (accessKeyId, accessKeySecret, appKey, region) at startup and fail the boot if any is missing.","Restrict region to the supported AliyunNlsRegion set so an internal/public endpoint mismatch cannot produce a bad signature.","Keep host clocks NTP-synced so the signed Timestamp stays inside Aliyun's allowed skew window.","Log (never echo the secret) the CreateToken response Message on failure so the provider's reason is always available."],"tags":["aliyun","nls","credentials","signature","cloud-provider","region","audio-transcription"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}