koala73/worldmonitor · error · ConvexError
NOT_FOUND
NOT_FOUND
Error message
NOT_FOUND
What it means
Thrown by the company update mutation (convex/companyMonitoring/companies.ts:202) when no companyMonitoringCompanies row exists for ownerAccountId + companyId, or the row has lifecycle "removed", or is missing name or domicileCountry. Updates are only allowed on live, fully-formed companies.
Solutions
- Refresh the company list and confirm the id still exists with lifecycle active/paused before showing an edit form
- If the company was removed, create a new company instead of updating the dead id
- Verify you are calling with the correct ownerUserId (the account that owns the company)
- Handle NOT_FOUND by returning the user to the list view rather than retrying
Example fix
// before
await api.companyMonitoring.updateCompany({ ownerUserId, companyId, patch });
// after
const company = await api.companyMonitoring.getCompany({ ownerUserId, companyId });
if (!company || company.lifecycle === "removed") {
router.replace("/companies"); // stale reference; reload list
return;
}
await api.companyMonitoring.updateCompany({ ownerUserId, companyId, patch }); Defensive patterns
Strategy: validation
Validate before calling
const company = await api.companyMonitoring.getCompany({ ownerUserId, companyId });
const updatable = !!company && company.lifecycle !== "removed" && !!company.name && !!company.domicileCountry;
if (!updatable) {
throw new UserFacingError("Company not found or no longer editable.");
}
await api.companyMonitoring.updateCompany({ ownerUserId, companyId, patch }); Type guard
function isEditableCompany(company: { lifecycle: string; name?: string; domicileCountry?: string } | null | undefined): company is { lifecycle: string; name: string; domicileCountry: string } {
return !!company && company.lifecycle !== "removed" && typeof company.name === "string" && typeof company.domicileCountry === "string";
} Try / catch
try {
await api.companyMonitoring.updateCompany({ ownerUserId, companyId, patch });
} catch (err) {
if (err instanceof ConvexError && err.data === "NOT_FOUND") {
router.replace("/companies"); // stale reference — reload the list
return;
}
throw err;
} Prevention
- Load the company fresh before rendering an edit form; do not trust cached lists
- Send users back to the list view on NOT_FOUND instead of retrying
- Confirm ownerUserId matches the account that owns the company
- Treat removed companies as gone: offer creation, not editing
When it happens
Trigger: Calling update with a companyId from another account or a typo'd id; updating a company already removed (removal is terminal); updating a company whose required fields were somehow cleared; stale client state referencing a deleted company.
Common situations: Two admin sessions where one removed the company; client caches holding an old company list; id mix-ups between environments (staging id sent to production); import scripts re-running against already-removed rows.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-08-21).
Data as JSON: /api/errors/f874fde33a9f914d.
Report an issue: GitHub.
Appendix: source
Thrown at convex/companyMonitoring/companies.ts:202
},
});
export const updateCompanyForOwner = internalMutation({
args: {
ownerUserId: v.string(),
companyId: v.string(),
patch: companyPatchValidator,
},
handler: async (ctx, args) => {
const account = await requireActiveAccount(ctx, args.ownerUserId);
const company = await ctx.db
.query("companyMonitoringCompanies")
.withIndex("by_account_companyId", (q) =>
q.eq("ownerAccountId", account.logicalAccountId).eq("companyId", args.companyId),
)
.unique();
if (!company || company.lifecycle === "removed" || !company.name || !company.domicileCountry) {
throw new ConvexError("NOT_FOUND");
}
const patch = args.patch;
const addClaimInputs = patch.addClaims ?? [];
const removeClaimInputs = patch.removeClaimIds ?? [];
if (
addClaimInputs.length > COMPANY_MONITORING_LIMITS.maxClaimsPerCompany ||
removeClaimInputs.length > COMPANY_MONITORING_LIMITS.maxClaimsPerCompany
) {
throw new ConvexError("INVALID_COMPANY_PATCH");
}
const hasName = Object.prototype.hasOwnProperty.call(patch, "name");
const hasDomicile = Object.prototype.hasOwnProperty.call(patch, "domicileCountry");
const hasCustomerReference = Object.prototype.hasOwnProperty.call(patch, "customerReference");
const normalizedFields = normalizeMonitoredCompanyInput({
name: hasName ? patch.name! : company.name,
domicileCountry: hasDomicile ? patch.domicileCountry! : company.domicileCountry,
customerReference: hasCustomerReferenceView on GitHub (pinned to 7d06c8633d)