twentyhq/twenty · error · Error

completeFileUpload mutation did not return a file id

Error message

completeFileUpload mutation did not return a file id

What it means

After the media bytes are uploaded to the presigned URL, the flow calls the metadata `completeFileUpload` mutation with the `fileId` to finalize the upload and receive the canonical file id. If `mutationResult.completeFileUpload?.id` is undefined, finalization did not return an id and the flow throws. This typically means the upload never completed server-side or the fileId is unknown to the server.

Source

Thrown at packages/twenty-apps/public/call-recorder/src/logic-functions/flows/import-call-recording-media.util.ts:356

};

const completeFileUpload = async ({
  metadataClient,
  fileId,
}: {
  metadataClient: InstanceType<typeof MetadataApiClient>;
  fileId: string;
}): Promise<string> => {
  const mutationResult = await metadataClient.mutation({
    completeFileUpload: {
      __args: { fileId },
      id: true,
    },
  });
  const uploadedFileId = mutationResult.completeFileUpload?.id;

  if (isUndefined(uploadedFileId)) {
    throw new Error('completeFileUpload mutation did not return a file id');
  }

  return uploadedFileId;
};

const parseContentLengthBytes = (
  headerValue: string | null,
): number | undefined => {
  if (!isNonEmptyString(headerValue)) {
    return undefined;
  }

  const parsedBytes = Number(headerValue.trim());

  return Number.isFinite(parsedBytes) && parsedBytes >= 0
    ? parsedBytes
    : undefined;
};

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Confirm the upstream PUT to `uploadUrl` succeeded (capture its status) before calling `completeFileUpload`.
  2. Ensure the `fileId` passed in is exactly the one returned by the preceding `createFileUpload` call in this same flow.
  3. Log `mutationResult` in full (including `errors`) to surface the server's reason for omitting the id.
  4. If finalization is transiently failing, retry the `completeFileUpload` mutation with backoff before aborting the whole import.

Example fix

// before
const uploadedFileId = mutationResult.completeFileUpload?.id;
if (isUndefined(uploadedFileId)) {
  throw new Error('completeFileUpload mutation did not return a file id');
}

// after — include the fileId and any server errors in the message
const uploadedFileId = mutationResult.completeFileUpload?.id;
if (isUndefined(uploadedFileId)) {
  throw new Error(
    `completeFileUpload mutation did not return a file id for fileId=${fileId}; server errors: ${JSON.stringify(mutationResult.errors ?? [])}`,
  );
}
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the PUT to the presigned URL succeeded before completing.
if (!uploadOk) {
  throw new Error(`Cannot completeFileUpload for ${fileId}: upstream PUT did not succeed`);
}

Type guard

const hasCompletedFileId = (r: unknown): r is { completeFileUpload: { id: string } } =>
  typeof r === 'object' &&
  r !== null &&
  typeof (r as any).completeFileUpload?.id === 'string';

Try / catch

async function completeWithRetry(metadataClient: any, fileId: string, attempts = 3): Promise<string> {
  let lastErr: unknown;
  for (let i = 0; i < attempts; i++) {
    try {
      const r = await metadataClient.mutation({ completeFileUpload: { __args: { fileId }, id: true } });
      if (typeof r.completeFileUpload?.id === 'string') return r.completeFileUpload.id;
      lastErr = new Error('completeFileUpload returned no id');
    } catch (e) { lastErr = e; }
    await new Promise((res) => setTimeout(res, 2 ** i * 400));
  }
  throw lastErr;
}

Prevention

When it happens

Trigger: The PUT to the presigned `uploadUrl` failed or was incomplete so the server has no finalized file; the `fileId` passed to `completeFileUpload` does not match the one returned by `createFileUpload`; the server rejected finalization (quota, virus scan, size) and returned a null/error shape.

Common situations: A network blip during the PUT leaving the multipart upload incomplete; passing a stale `fileId` from a previous attempt; a server-side post-upload validation rejecting the file.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/6dae3712b5253022. Report an issue: GitHub.