jackwener/OpenCLI · error · CommandExecutionError

申请抖音上传地址响应缺少必要字段: ${JSON.stringify(payload).slice(0, 500)}

Error message

申请抖音上传地址响应缺少必要字段: ${JSON.stringify(payload).slice(0, 500)}

What it means

The ApplyUploadInner call succeeded (HTTP ok, no ResponseMetadata.Error) but the response lacks required upload fields: UploadHost, StoreUri, StoreInfo.Auth, Vid, or SessionKey. The library cannot construct the TOS upload URL or commit key without them, so it fails fast with a truncated payload dump (first 500 chars).

Source

Thrown at clis/douyin/_shared/vod-upload.js:158

  const url = `${VOD_UPLOAD_HOST}?${params.toString()}`;
  const res = await fetch(url, { headers: computeAws4Headers(url, credentials), signal: AbortSignal.timeout(30000) });
  const text = await res.text();
  let payload;
  try {
    payload = JSON.parse(text);
  } catch {
    throw new CommandExecutionError(`申请抖音上传地址失败,非 JSON 响应: HTTP ${res.status} ${text.slice(0, 300)}`);
  }
  const error = payload?.ResponseMetadata?.Error;
  if (!res.ok || error) {
    throw new CommandExecutionError(`申请抖音上传地址失败: HTTP ${res.status} ${JSON.stringify(error ?? payload)}`);
  }
  const uploadNode = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0];
  const storeInfo = uploadNode?.StoreInfos?.[0];
  const videoId = payload?.Result?.Vid || uploadNode?.Vid;
  const sessionKey = uploadNode?.SessionKey ?? storeInfo?.SessionKey ?? payload?.Result?.SessionKey;
  if (!uploadNode?.UploadHost || !storeInfo?.StoreUri || !storeInfo?.Auth || !videoId || !sessionKey) {
    throw new CommandExecutionError(`申请抖音上传地址响应缺少必要字段: ${JSON.stringify(payload).slice(0, 500)}`);
  }
  return {
    video_id: videoId,
    tos_upload_url: `https://${uploadNode.UploadHost}/${storeInfo.StoreUri}`,
    auth: storeInfo.Auth,
    session_key: sessionKey,
    upload_header: uploadNode.UploadHeader ?? {},
    user_id: credentials.user_id ?? '',
  };
}


export async function commitVideoUploadInner(uploadInfo, credentials) {
  if (!uploadInfo?.session_key) {
    throw new CommandExecutionError('抖音上传提交缺少 SessionKey');
  }
  const params = new URLSearchParams({
    Action: 'CommitUploadInner',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the payload dump in the message to see which fields are missing and where the data actually lives.
  2. Update the extraction paths in applyVideoUploadInner to match the current response schema if Douyin changed it.
  3. Verify the account/space still allows inner uploads (empty UploadNodes may indicate a permission/quota problem).
  4. Retry once — occasionally a degraded response is transient.
  5. Update the CLI/library if a Douyin API version bump altered the upload address structure.

Example fix

// before
const uploadNode = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0];
// after
const uploadNode = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0]
  ?? payload?.Result?.UploadAddress?.UploadNodes?.[0]; // tolerate schema variants
Defensive patterns

Strategy: validation

Validate before calling

function hasUploadAddress(payload) {
  const node = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0];
  const store = node?.StoreInfos?.[0];
  return Boolean(node?.UploadHost && store?.StoreUri && store?.Auth
    && (payload?.Result?.Vid || node?.Vid)
    && (node?.SessionKey ?? store?.SessionKey ?? payload?.Result?.SessionKey));
}

Type guard

null

Try / catch

try {
  uploadInfo = await applyVideoUploadInner(fileSize, creds);
} catch (e) {
  if (/缺少必要字段/.test(e.message)) {
    console.error('实际响应:', e.message); // adapt extraction paths to schema drift
  }
  throw e;
}

Prevention

When it happens

Trigger: payload.Result.InnerUploadAddress.UploadNodes is empty or missing StoreInfos[0]; Vid and SessionKey absent from all expected locations — typically schema drift or an empty/degraded success response.

Common situations: Douyin changed the response nesting (renamed InnerUploadAddress/UploadNodes/StoreInfos); zero upload nodes returned because the space/quota is misconfigured; a partially migrated API version returns a new shape.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/ed242765c07e3910. Report an issue: GitHub.