twentyhq/twenty · error · Error

createFileUpload mutation did not return an upload target

Error message

createFileUpload mutation did not return an upload target

What it means

Before uploading media bytes, the flow calls the metadata `createFileUpload` mutation to obtain an upload target (`fileId`, `uploadUrl`, `contentType`). If the mutation result's `createFileUpload` field is `undefined`, the server did not return an upload target, so there is nowhere to PUT the bytes and the flow throws. The genql client returns `undefined` for a field the server omitted or for a union/error shape it did not select.

Source

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

  fieldMetadataUniversalIdentifier: string;
}): Promise<MediaUploadTarget> => {
  const mutationResult = await metadataClient.mutation({
    createFileUpload: {
      __args: {
        filename: fileName,
        size: sizeBytes,
        fileFolder: MEDIA_FILE_FOLDER,
        fieldMetadataUniversalIdentifier,
      },
      fileId: true,
      uploadUrl: true,
      contentType: true,
    },
  });
  const uploadTarget = mutationResult.createFileUpload;

  if (isUndefined(uploadTarget)) {
    throw new Error(
      'createFileUpload mutation did not return an upload target',
    );
  }

  return uploadTarget;
};

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

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Verify `CALL_RECORDING_AUDIO_FIELD_UNIVERSAL_IDENTIFIER` / `CALL_RECORDING_VIDEO_FIELD_UNIVERSAL_IDENTIFIER` resolve to existing file-type fields on the call-recording object in this workspace.
  2. Check the metadata client is authenticated with a role that can create file uploads on the call-recording object.
  3. Log the full `mutationResult` (including any `errors` array from the genql response) to see the server-side reason the field was omitted.
  4. Confirm `sizeBytes` is within the server's per-upload limit and that `fileFolder: 'FilesField'` is valid for this object.

Example fix

// before
const uploadTarget = mutationResult.createFileUpload;
if (isUndefined(uploadTarget)) {
  throw new Error('createFileUpload mutation did not return an upload target');
}

// after — surface server errors and the requested identifier
const uploadTarget = mutationResult.createFileUpload;
if (isUndefined(uploadTarget)) {
  throw new Error(
    `createFileUpload mutation did not return an upload target for ${fileName} (field=${fieldMetadataUniversalIdentifier}, size=${sizeBytes}); server errors: ${JSON.stringify(mutationResult.errors ?? [])}`,
  );
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: confirm the file field exists before requesting an upload target.
const fieldExists = await metadataClient.query({
  fields: { __args: { filter: { universalIdentifier: { eq: fieldMetadataUniversalIdentifier } } }, edges: { node: { id: true } } },
});
if (!fieldExists.fields?.edges?.length) {
  throw new Error(`File field ${fieldMetadataUniversalIdentifier} not found; cannot create upload target`);
}

Type guard

const isUploadTarget = (v: unknown): v is { fileId: string; uploadUrl: string; contentType: string } =>
  typeof v === 'object' &&
  v !== null &&
  typeof (v as any).fileId === 'string' &&
  typeof (v as any).uploadUrl === 'string' &&
  typeof (v as any).contentType === 'string';

Prevention

When it happens

Trigger: The `fieldMetadataUniversalIdentifier` passed in does not match a file field on the object (so the server refuses to create an upload target), the authenticated user lacks permission to upload, the file size exceeds a server limit expressed as a null response, or the server returned an error payload that genql surfaces as an unset field.

Common situations: The audio/video field universal identifiers were renamed/removed; running against a workspace where the Call Recorder object/fields were not installed; permission/role misconfiguration on the installing user; a server-side upload quota reached.

Related errors


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