Skip to content

Fix duplicate resource errors from throwing 500 instead of user frien…#2262

Merged
sarah-inkeep merged 5 commits into
mainfrom
prd-6088
Feb 23, 2026
Merged

Fix duplicate resource errors from throwing 500 instead of user frien…#2262
sarah-inkeep merged 5 commits into
mainfrom
prd-6088

Conversation

@sarah-inkeep
Copy link
Copy Markdown
Contributor

…dly error message

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agents-api Ready Ready Preview, Comment Feb 23, 2026 8:21pm
agents-docs Ready Ready Preview, Comment Feb 23, 2026 8:21pm
agents-manage-ui Ready Ready Preview, Comment Feb 23, 2026 8:21pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 23, 2026

🦋 Changeset detected

Latest commit: 85f6790

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@inkeep/agents-work-apps Patch
@inkeep/agents-core Patch
@inkeep/agents-api Patch
@inkeep/agents-manage-ui Patch
@inkeep/agents-cli Patch
@inkeep/agents-sdk Patch
@inkeep/ai-sdk-provider Patch
@inkeep/create-agents Patch
@inkeep/agents-mcp Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review Summary

(4) Total Issues | Risk: Medium

🟠⚠️ Major (1) 🟠⚠️

🟠 1) packages/agents-core/src/utils/error.ts:293-308 Missing unit tests for new helper functions

Issue: The new isUniqueConstraintError() and throwIfUniqueConstraintError() functions have no dedicated unit tests. These functions detect unique constraint violations via three patterns: PostgreSQL code 23505, Doltgres MySQL errno 1062, and "already exists" message fallback.

Why: These functions are critical error-handling utilities used across 7 route handlers. The existing integration tests run against pglite (PostgreSQL), so only the '23505' path is tested. The Doltgres '1062' pattern and "already exists" fallback are never exercised in tests. If the detection logic regresses, Doltgres deployments would return 500 instead of 409 for duplicate resources.

Fix: Add unit tests in packages/agents-core/src/utils/__tests__/error.test.ts:

import { describe, it, expect } from 'vitest';
import { isUniqueConstraintError, throwIfUniqueConstraintError } from '../error';
import { HTTPException } from 'hono/http-exception';

describe('isUniqueConstraintError', () => {
  it('should detect PostgreSQL unique violation code 23505', () => {
    const error = { cause: { code: '23505' } };
    expect(isUniqueConstraintError(error)).toBe(true);
  });

  it('should detect Doltgres MySQL errno 1062 in cause message', () => {
    const error = { cause: { message: 'Error 1062: Duplicate entry' } };
    expect(isUniqueConstraintError(error)).toBe(true);
  });

  it('should detect "already exists" in error message', () => {
    const error = { message: 'Resource already exists' };
    expect(isUniqueConstraintError(error)).toBe(true);
  });

  it('should return false for unrelated errors', () => {
    expect(isUniqueConstraintError({ message: 'Connection timeout' })).toBe(false);
    expect(isUniqueConstraintError(null)).toBe(false);
  });
});

describe('throwIfUniqueConstraintError', () => {
  it('should throw 409 HTTPException for unique constraint errors', () => {
    const error = { cause: { code: '23505' } };
    expect(() => throwIfUniqueConstraintError(error, 'Resource conflict'))
      .toThrow(HTTPException);
  });

  it('should not throw for non-unique-constraint errors', () => {
    const error = { message: 'Network error' };
    expect(() => throwIfUniqueConstraintError(error, 'ignored')).not.toThrow();
  });
});

Refs:

🟡 Minor (2) 🟡

🟡 1) packages/agents-core/src/utils/error.ts:301 Broad "already exists" fallback pattern

Issue: The generic fallback err?.message?.includes('already exists') can match errors unrelated to database unique constraints (e.g., file system errors, application validation, downstream service errors).
Why: False positives could convert legitimate 500 errors into misleading 409 Conflict responses. However, this preserves existing behavior from the routes being refactored.
Fix: Consider making the fallback more specific in a follow-up, e.g., checking for cause structure or more specific message patterns like "unique constraint" or "duplicate key".
Refs: error.ts:301

🟡 2) packages/agents-work-apps/src/slack/routes/oauth.ts:334-338 Missed migration: oauth.ts still uses manual duplicate detection

Issue: The PR standardizes unique constraint detection with isUniqueConstraintError, but oauth.ts in the same package still uses manual string matching.
Why: Creates inconsistency within agents-work-apps where users.ts was updated but oauth.ts was not.
Fix: Update oauth.ts to use isUniqueConstraintError for consistency:

// Replace lines 334-338
if (isUniqueConstraintError(dbError)) {

Refs: oauth.ts:334-338

💭 Consider (2) 💭

Inline Comments:

  • 💭 Consider: projects.ts:261 Stale comment still mentions "PostgreSQL" only
  • 🟡 Minor: projectFull.ts:196 Error logged at ERROR level before unique constraint check

🧹 While You're Here (2) 🧹

🧹 1) packages/agents-work-apps/src/slack/routes/users.ts:261-265 Inconsistent API response shape on race condition

Issue: When isUniqueConstraintError catches a duplicate, the endpoint returns { success: true } but omits fields (linkId, slackUsername, etc.) that are returned on successful creation.
Why: Callers can't distinguish between new creation vs pre-existing mapping. Pre-existing issue, not introduced by this PR.
Fix: Consider fetching and returning the existing mapping for consistent response shape.
Refs: users.ts:261-265

🧹 2) agents-api/src/domains/manage/routes/subAgent*.ts Inconsistent error codes for duplicates

Issue: The new helper uses 409 conflict for duplicate resources, but several subAgent relation routes use 422 unprocessable_entity for the same semantic condition.
Why: Inconsistent error taxonomy for API consumers. Pre-existing pattern, not introduced by this PR.
Fix: Consider standardizing on 409 for all duplicate/conflict scenarios, or documenting the intentional distinction.
Refs: subAgentRelations.ts:202-206


💡 APPROVE WITH SUGGESTIONS

Summary: Good refactoring that centralizes duplicate resource error handling and improves user experience by returning proper 409 Conflict responses instead of 500 errors. The main actionable item is adding unit tests for the new helper functions to ensure Doltgres error detection doesn't regress. The changeset is well-written and the implementation is clean.

Discarded (3)
Location Issue Reason Discarded
AgentSession.ts:1799-1804 Manual duplicate detection not using new helper Different error-handling context (silent session management) where throwing isn't appropriate
Integration test lenient assertion Test accepts 409 or 500 Pre-existing workaround; cleaning it up is out of scope for this PR
Positive feedback on naming Helper naming follows patterns Not an issue - informational only
Reviewers (4)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-tests 2 1 0 0 0 0 1
pr-review-errors 3 1 1 1 1 0 0
pr-review-consistency 5 1 1 1 1 0 1
pr-review-standards 0 0 0 0 0 0 0
Total 10 3 2 2 2 0 2

Note: pr-review-standards returned no findings, indicating the code quality and AGENTS.md compliance are good.

@@ -258,12 +259,7 @@ app.openapi(
);
} catch (error: any) {
// Handle duplicate project (PostgreSQL unique constraint violation)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Consider: Stale comment

Issue: The comment still mentions "PostgreSQL unique constraint violation" but the new helper handles both PostgreSQL and Doltgres errors.

Why: Outdated comments can mislead future maintainers about the actual behavior.

Fix:

Suggested change
// Handle duplicate project (PostgreSQL unique constraint violation)
} catch (error: any) {
throwIfUniqueConstraintError(error, 'Project with this ID already exists');

Refs:

@@ -193,14 +194,8 @@ app.openapi(

return c.json({ data: createdProject }, 201);
} catch (error: any) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Minor: Error logging at wrong level for expected user errors

Issue: logger.error() is called before checking for unique constraint errors, meaning expected duplicate creation attempts (which return 409 to users) are logged at ERROR level.

Why: Logging expected user errors at ERROR level creates noise in monitoring, potentially triggering unnecessary alerts and making it harder to spot real issues.

Fix: Move the error log after the unique constraint check, or log at INFO level for duplicates:

Suggested change
} catch (error: any) {
} catch (error: any) {
if (isUniqueConstraintError(error)) {
logger.info({ projectId: projectData.id }, 'Duplicate project creation attempted');
throwIfUniqueConstraintError(error, `Project with ID '${projectData.id}' already exists`);
}
logger.error({ error }, 'Error creating project');

Note: This would require importing isUniqueConstraintError separately from throwIfUniqueConstraintError.

Refs:

@github-actions github-actions Bot deleted a comment from claude Bot Feb 23, 2026
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review Summary

(1) Total Issues | Risk: Low

This is a delta re-review. The previous review raised 4 issues — 3 have been addressed in the follow-up commits, 1 remains applicable.

✅ Findings Addressed Since Last Review

Prior Finding Status Resolution
🟠 Major: Missing unit tests for isUniqueConstraintError Addressed Comprehensive test suite added in error.test.ts (106 lines, 15 test cases covering PostgreSQL 23505, Doltgres 1062, "already exists" fallback, and edge cases)
🟡 Minor: oauth.ts not migrated to use helper Addressed Now imports and uses isUniqueConstraintError consistently
💭 Consider: Stale comment mentioning only PostgreSQL Addressed Comment removed in projects.ts

🕐 Pending Recommendations (1)

  • 🟡 projectFull.ts:196 Error logging at ERROR level before unique constraint check (expected user errors logged as errors creates monitoring noise)

✅ APPROVE

Summary: Excellent follow-up work! The unit tests are thorough and well-structured, covering all three detection patterns (PostgreSQL 23505, Doltgres 1062, and the "already exists" fallback). The oauth.ts migration was completed as suggested. The one pending item (error logging level) is minor and doesn't block — it can be addressed in a follow-up if desired. Ship it! 🚀

Discarded (0)

No items discarded in this delta review.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched 0 0 0 0 0 0 0
Total 0 0 0 0 0 0 0

Note: This was a delta re-review where all new changes addressed prior feedback. No new sub-reviewers were needed.

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review Summary

(0) New Issues | Risk: Low

This is a delta re-review (3rd review cycle). The changes since the last review are merge commits from main only (#2085 Slack workspace default agent clear/reset, #2159 scope config types refactor) — no modifications to this PR's duplicate error handling feature.

✅ PR Status

All prior feedback has been addressed except one minor item:

Prior Finding Current Status
🟠 Major: Missing unit tests ✅ Addressed (106-line test suite added)
🟡 Minor: oauth.ts not using helper ✅ Addressed
💭 Consider: Stale PostgreSQL comment ✅ Addressed
🟡 Minor: Error logging level ⏳ Still applicable (non-blocking)

🕐 Pending Recommendations (1)

  • 🟡 projectFull.ts:196 Error logging at ERROR level before unique constraint check (expected user errors logged as errors creates monitoring noise)

✅ APPROVE

Summary: No new issues in this delta — just merge commits from main. The original feature is well-tested and ready to ship. The one pending logging-level suggestion is minor and can be addressed in a follow-up if desired. 🚀

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched 0 0 0 0 0 0 0
Total 0 0 0 0 0 0 0

Note: Delta contained only merge commits from main — no sub-reviewers needed.

Copy link
Copy Markdown
Collaborator

@amikofalvy amikofalvy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ship this, but we agreed to work on some broader fixes for this class of problems later this week

@sarah-inkeep sarah-inkeep merged commit eea5f0a into main Feb 23, 2026
13 checks passed
@sarah-inkeep sarah-inkeep deleted the prd-6088 branch February 23, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants