twentyhq/twenty · error · Error
createOpportunity did not return an id
Error message
createOpportunity did not return an id
What it means
submitClientBrief calls createOpportunity and asserts createOpportunity.id before notifying on the new opportunity. Same guard shape as the TFT importer: the server returned a null/empty createOpportunity instead of throwing. The service's outer try/catch converts it to { ok: false, reason }.
Source
Thrown at packages/twenty-apps/internal/twenty-partners/src/modules/opportunity/intake/services/submit-client-brief.service.ts:70
const opportunityData: CoreSchema.OpportunityCreateInput = {
name,
need: input.need,
isListed: false,
stage: 'NEW',
companyId,
pointOfContactId,
};
if (requirements !== null) {
opportunityData.requirements = requirements;
}
if (referringPartner !== null) {
opportunityData.referredByPartnerId = referringPartner.id;
}
const result = await createOpportunity(client, opportunityData);
const opportunityId = result.createOpportunity?.id;
if (opportunityId === undefined) {
throw new Error('createOpportunity did not return an id');
}
await notifyClientBrief({ opportunityId, input, referringPartner });
return { ok: true, opportunityId };
} catch (err) {
return { ok: false, reason: err instanceof Error ? err.message : String(err) };
}
}
View on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Check the returned SubmitClientBriefResult.reason — it echoes this message.
- Inspect the raw createOpportunity response (null payload vs. errors array).
- Validate opportunityData required fields and relation ids (companyId, referredByPartnerId) before the call.
- Confirm the caller's role has Opportunity create permission and the object is synced.
Example fix
// before
const result = await createOpportunity(client, opportunityData);
const opportunityId = result.createOpportunity?.id;
if (opportunityId === undefined) {
throw new Error('createOpportunity did not return an id');
}
// after — richer reason for the caller
const result = await createOpportunity(client, opportunityData);
const opportunityId = result.createOpportunity?.id;
if (opportunityId === undefined) {
throw new Error(
`createOpportunity did not return an id (referringPartner=${referringPartner?.id ?? 'none'}, result=${JSON.stringify(result)})`,
);
} Defensive patterns
Strategy: try-catch
Validate before calling
function assertClientBriefOpportunityData(data: Record<string, unknown>) {
if (!data.stage) throw new Error('opportunityData.stage is required');
if (requirements !== null) data.requirements = requirements; // ensure non-null
}
assertClientBriefOpportunityData(opportunityData); Type guard
const hasCreatedOpportunityId = (r: unknown): r is { createOpportunity: { id: string } } =>
typeof r === 'object' && r !== null &&
typeof (r as any).createOpportunity?.id === 'string';
if (!hasCreatedOpportunityId(result)) {
throw new Error(`createOpportunity returned no id: ${JSON.stringify(result)}`);
} Try / catch
// submitClientBrief already wraps this in try/catch returning { ok, reason }.
// Callers branch on result.ok:
const res = await submitClientBrief(input);
if (!res.ok) {
logger.warn('client brief submit failed', { reason: res.reason });
return;
} Prevention
- Check SubmitClientBriefResult.ok before using opportunityId.
- Validate opportunity required fields and relation ids (companyId, referredByPartnerId) before the create.
- Log the raw createOpportunity response when the id is missing.
- Confirm Opportunity create permission.
When it happens
Trigger: createOpportunity returns null or an id-less payload. Triggered by missing required fields in opportunityData, an invalid referringPartnerId/referredByPartnerId relation, server-side validation failure, or insufficient Opportunity create permission.
Common situations: Submitting a client brief with incomplete requirements or an unknown referring partner; role lacks Opportunity create; metadata drift; amount/stage outside allowed value list.
Related errors
- createOpportunity did not return an id
- createCompany did not return an id
- createPerson did not return an id
- createCompany did not return an id
- createPartner did not return an id
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/aeeecf22c37949b9.
Report an issue: GitHub.