Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .devwork/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Execution Plan

## Tasks: 6

{
"summary": "This PR fixes a schema mismatch between server error responses and client expectations. The server returns HTTP 200 with `{ error: ... }` body, but client only accepted `{ success: boolean }`. The plan verifies the changes are applied and runs tests to confirm the fix works.",
"tasks": [
{
"id": "T001",
"tool": "Bash",
"args": {"command": "ls -la /tmp/claudev-pr-96453/packages/core/src/v3/schemas/api.ts /tmp/claudev-pr-96453/packages/cli-v3/src/commands/deploy.ts /tmp/claudev-pr-96453/packages/core/test/environmentVariableResponse.test.ts 2>&1"},
"depends_on": [],
"description": "Verify the three affected files exist"
},
{
"id": "T002",
"tool": "Bash",
"args": {"command": "grep -A10 \"EnvironmentVariableResponseBody\" /tmp/claudev-pr-96453/packages/core/src/v3/schemas/api.ts | head -20"},
"depends_on": ["T001"],
"description": "Verify schema changes in api.ts"
},
{
"id": "T003",
"tool": "Bash",
"args": {"command": "grep -n \"error.*uploadResult.data\" /tmp/claudev-pr-96453/packages/cli-v3/src/commands/deploy.ts | head -5"},
"depends_on": ["T001"],
"description": "Verify error handling in deploy.ts"
},
{
"id": "T004",
"tool": "Bash",
"args": {"command": "cd /tmp/claudev-pr-96453 && npm run build --workspace=packages/core 2>&1 | tail -20"},
"depends_on": ["T002", "T003"],
"description": "Build the core package to verify schema compiles"
},
{
"id": "T005",
"tool": "Bash",
"args": {"command": "cd /tmp/claudev-pr-96453 && npm run build --workspace=packages/cli-v3 2>&1 | tail -20"},
"depends_on": ["T004"],
"description": "Build cli-v3 package to verify deploy.ts compiles"
},
{
"id": "T006",
"tool": "Bash",
"args": {"command": "cd /tmp/claudev-pr-96453 && npm run test --workspace=packages/core -- --run environmentVariableResponse 2>&1"},
"depends_on": ["T004"],
"description": "Run the new test file to verify schema validation works"
}
]
}
47 changes: 47 additions & 0 deletions .devwork/plan_response.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"summary": "This PR fixes a schema mismatch between server error responses and client expectations. The server returns HTTP 200 with `{ error: ... }` body, but client only accepted `{ success: boolean }`. The plan verifies the changes are applied and runs tests to confirm the fix works.",
"tasks": [
{
"id": "T001",
"tool": "Bash",
"args": {"command": "ls -la /tmp/claudev-pr-96453/packages/core/src/v3/schemas/api.ts /tmp/claudev-pr-96453/packages/cli-v3/src/commands/deploy.ts /tmp/claudev-pr-96453/packages/core/test/environmentVariableResponse.test.ts 2>&1"},
"depends_on": [],
"description": "Verify the three affected files exist"
},
{
"id": "T002",
"tool": "Bash",
"args": {"command": "grep -A10 \"EnvironmentVariableResponseBody\" /tmp/claudev-pr-96453/packages/core/src/v3/schemas/api.ts | head -20"},
"depends_on": ["T001"],
"description": "Verify schema changes in api.ts"
},
{
"id": "T003",
"tool": "Bash",
"args": {"command": "grep -n \"error.*uploadResult.data\" /tmp/claudev-pr-96453/packages/cli-v3/src/commands/deploy.ts | head -5"},
"depends_on": ["T001"],
"description": "Verify error handling in deploy.ts"
},
{
"id": "T004",
"tool": "Bash",
"args": {"command": "cd /tmp/claudev-pr-96453 && npm run build --workspace=packages/core 2>&1 | tail -20"},
"depends_on": ["T002", "T003"],
"description": "Build the core package to verify schema compiles"
},
{
"id": "T005",
"tool": "Bash",
"args": {"command": "cd /tmp/claudev-pr-96453 && npm run build --workspace=packages/cli-v3 2>&1 | tail -20"},
"depends_on": ["T004"],
"description": "Build cli-v3 package to verify deploy.ts compiles"
},
{
"id": "T006",
"tool": "Bash",
"args": {"command": "cd /tmp/claudev-pr-96453 && npm run test --workspace=packages/core -- --run environmentVariableResponse 2>&1"},
"depends_on": ["T004"],
"description": "Run the new test file to verify schema validation works"
}
]
}
210 changes: 210 additions & 0 deletions .devwork/prompt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
# PR #2: Fix environment variables validation error during deployment

## Description
This PR fixes the deployment error: "Failed to fetch environment variables: 200 Validation error: Required" that occurs when syncing environment variables during deployment.

## Problem

The error occurred due to a schema mismatch between the server's error responses and the client's expectations:

1. The server endpoint `/api/v1/projects/$projectRef/envvars/$slug/import` returns error responses like `{ error: "...", variableErrors: [...] }` with HTTP 200 status
2. The client's `EnvironmentVariableResponseBody` schema only accepted `{ success: boolean }`
3. When the server returned an error in the response body, schema validation failed with "Required" because the `success` field was missing

## Solution

### Schema Changes
- Updated `EnvironmentVariableResponseBody` to be a union type that accepts both:
- Success responses: `{ success: true }`
- Error responses: `{ error: string, variableErrors?: any[] }`

### Client Logic Changes
- Enhanced the deploy command to handle server errors returned in the response body (HTTP 200 with error) in addition to HTTP error status codes
- Added proper error messaging for server-side validation failures

## Testing

- Added comprehensive test coverage for the new schema validation
- Verified that all existing functionality continues to work as expected
- Tested both success and error scenarios to ensure proper handling

The fix is minimal and surgical - it only affects the specific validation error without changing any other behavior, ensuring backward compatibility while resolving the deployment issue.

Fixes #1.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more addresses</summary>
>
> #### I tried to connect to the following addresses, but was blocked by firewall rules:
>
> - `binaries.prisma.sh`
>
> If you need me to access, download, or install something from one of these locations, you can either:
>
> - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before t
... (truncated)

## Diff
```diff
diff --git a/packages/cli-v3/src/commands/deploy.ts b/packages/cli-v3/src/commands/deploy.ts
index 5c7304eff3..09f66c2fcd 100644
--- a/packages/cli-v3/src/commands/deploy.ts
+++ b/packages/cli-v3/src/commands/deploy.ts
@@ -392,6 +392,18 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
"",
$spinner
);
+ } else if ("error" in uploadResult.data) {
+ // Server returned 200 but with error in body
+ await failDeploy(
+ projectClient.client,
+ deployment,
+ {
+ name: "SyncEnvVarsError",
+ message: `Failed to sync ${numberOfEnvVars} env ${vars} with the server: ${uploadResult.data.error}`,
+ },
+ "",
+ $spinner
+ );
} else {
$spinner.stop(`Successfully synced ${numberOfEnvVars} env ${vars} with the server`);
}
diff --git a/packages/core/src/v3/schemas/api.ts b/packages/core/src/v3/schemas/api.ts
index b8819347bf..680be03f48 100644
--- a/packages/core/src/v3/schemas/api.ts
+++ b/packages/core/src/v3/schemas/api.ts
@@ -813,9 +813,15 @@ export type ImportEnvironmentVariablesRequestBody = z.infer<
typeof ImportEnvironmentVariablesRequestBody
>;

-export const EnvironmentVariableResponseBody = z.object({
- success: z.boolean(),
-});
+export const EnvironmentVariableResponseBody = z.union([
+ z.object({
+ success: z.literal(true),
+ }),
+ z.object({
+ error: z.string(),
+ variableErrors: z.array(z.any()).optional(),
+ }),
+]);

export type EnvironmentVariableResponseBody = z.infer<typeof EnvironmentVariableResponseBody>;

diff --git a/packages/core/test/environmentVariableResponse.test.ts b/packages/core/test/environmentVariableResponse.test.ts
new file mode 100644
index 0000000000..4107373ada
--- /dev/null
+++ b/packages/core/test/environmentVariableResponse.test.ts
@@ -0,0 +1,53 @@
+import { EnvironmentVariableResponseBody } from "../src/v3/schemas/api.js";
+
+describe("EnvironmentVariableResponseBody schema", () => {
+ it("should accept success response", () => {
+ const successResponse = { success: true };
+ const result = EnvironmentVariableResponseBody.safeParse(successResponse);
+
+ expect(result.success).toBe(true);
+ if (result.success) {
+ expect(result.data).toEqual({ success: true });
+ }
+ });
+
+ it("should accept error response with error field", () => {
+ const errorResponse = { error: "Something went wrong" };
+ const result = EnvironmentVariableResponseBody.safeParse(errorResponse);
+
+ expect(result.success).toBe(true);
+ if (result.success) {
+ expect(result.data).toEqual({ error: "Something went wrong" });
+ }
+ });
+
+ it("should accept error response with error and variableErrors fields", () => {
+ const errorResponse = {
+ error: "Variable validation failed",
+ variableErrors: ["Invalid variable name", "Value too long"]
+ };
+ const result = EnvironmentVariableResponseBody.safeParse(errorResponse);
+
+ expect(result.success).toBe(true);
+ if (result.success) {
+ expect(result.data).toEqual({
+ error: "Variable validation failed",
+ variableErrors: ["Invalid variable name", "Value too long"]
+ });
+ }
+ });
+
+ it("should reject response without success or error field", () => {
+ const invalidResponse = { something: "else" };
+ const result = EnvironmentVariableResponseBody.safeParse(invalidResponse);
+
+ expect(result.success).toBe(false);
+ });
+
+ it("should reject response with success: false", () => {
+ const invalidResponse = { success: false };
+ const result = EnvironmentVariableResponseBody.safeParse(invalidResponse);
+
+ expect(result.success).toBe(false);
+ });
+});
\ No newline at end of file
```

## Task
This PR fixes the deployment error: "Failed to fetch environment variables: 200 Validation error: Required" that occurs when syncing environment variables during deployment.

## Problem

The error occurred due to a schema mismatch between the server's error responses and the client's expectations:

1. The server endpoint `/api/v1/projects/$projectRef/envvars/$slug/import` returns error responses like `{ error: "...", variableErrors: [...] }` with HTTP 200 status
2. The client's `EnvironmentVariableResponseBody` schema only accepted `{ success: boolean }`
3. When the server returned an error in the response body, schema validation failed with "Required" because the `success` field was missing

## Solution

### Schema Changes
- Updated `EnvironmentVariableResponseBody` to be a union type that accepts both:
- Success responses: `{ success: true }`
- Error responses: `{ error: string, variableErrors?: any[] }`

### Client Logic Changes
- Enhanced the deploy command to handle server errors returned in the response body (HTTP 200 with error) in addition to HTTP error status codes
- Added proper error messaging for server-side validation failures

## Testing

- Added comprehensive test coverage for the new schema validation
- Verified that all existing functionality continues to work as expected
- Tested both success and error scenarios to ensure proper handling

The fix is minimal and surgical - it only affects the specific validation error without changing any other behavior, ensuring backward compatibility while resolving the deployment issue.

Fixes #1.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more addresses</summary>
>
> #### I tried to connect to the following addresses, but was blocked by firewall rules:
>
> - `binaries.prisma.sh`
>
> If you need me to access, download, or install something from one of these locations, you can either:
>
> - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to my [firewall allow list](https://gh.io/copilot/firewall-config)
>
> </details>


---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.
Loading