Troubleshooting

Symptom-first fixes for auth, CRUD, storage, AI, realtime, and deployment issues

Use this page when something looks broken and you need the shortest safe path from symptom to fix. Each row keeps the public contract small: no provider keys, session tokens, storage grant URLs, database URLs, or internal platform paths should appear in app code, logs, screenshots, or support posts.

Fast Checks

Symptom Likely cause Fix Verify
Frontend calls http://localhost:5456 after deploy The auth or API client was created without the deployed base URL Define one baseUrl from import.meta.env.VITE_API_URL and pass it to createAuthClient(baseUrl) and createGencowClient({ api, baseUrl, auth }) Browser network requests go to your *.gencow.app or custom domain backend
Expected object from a query Required object input was omitted, or the app is using an older runtime before optional-object args were normalized On current runtimes, useQuery(api.tasks.list) and useQuery(api.tasks.list, {}) both work for default CRUD lists. For required inputs, pass the full args object. CRUD list response is { data, total, nextCursor? }; required-input queries no longer run until args are present
result.map is not a function createCrud().list returns an object, not an array Render result.data.map(...) and use result.total for counts Empty lists render an empty state instead of crashing
Private file URL returns 403 Hosted storage is private by default Return a fresh ctx.storage.createReadGrant(storageId, { ttlSeconds }) URL for browser previews, or store intentionally public assets with { visibility: "public" } Private bare URL is 403, read grant URL is 200, public asset URL is 200
Login works locally but deployed frontend is logged out Auth lifecycle and query/mutation calls use different origins Use the same baseUrl for createAuthClient(baseUrl) and createGencowClient({ api, baseUrl, auth }) Sign in, refresh the page, then run an auth-required query
Realtime does not refresh a private list after a custom mutation Custom mutations do not know which query to refresh Call ctx.realtime.invalidate("tasks.list") after the write The subscribed useQuery(api.tasks.list, {}) refetches over HTTP with the user's JWT
AI request returns 402 or upgrade-required The selected model or service usage requires a higher plan or available service credits Pick an allowed model for the plan, reduce usage, or upgrade the plan Error code is user-actionable and appears before provider call side effects
AI request returns 429 Provider admission or service credit pacing is limiting the request Retry later with backoff, lower request size, or check plan/provider status Public logs show safe codes such as provider_tpm_limited, not raw prompts or provider keys
AI request returns 403 Auth, plan entitlement, storage grant, or provider credential state may be blocking the request First check app auth, plan/model access, and whether any private file was passed without a read grant The response body should be public-safe and should not include secrets
AI app redeploy fails with missing ai or @ai-sdk/openai Platform-provided dependency resolution drift Redeploy with the latest CLI/runtime after the platform fix is released; do not add provider keys to app code as a workaround Startup logs no longer show module resolution errors
gencow app create reports a platform error The platform rejected the request before App creation completed Keep the printed error Code and Correlation ID, confirm the App was not added with gencow app list, then retry only after platform health recovers or support confirms recovery A later create succeeds once, or support can trace the exact failed request without credentials or private logs
gencow deploy says the login expired or is invalid The saved login or an environment deploy token is no longer accepted by the selected Platform Follow the credential-source action printed by the CLI: log in again for saved credentials, or replace/unset the named GENCOW_TOKEN/GENCOW_DEPLOY_TOKEN variable gencow whoami and gencow app status <app> succeed against the intended Platform
Deploy reports a release-attempt conflict or recovery state The same app has a release attempt or linked deployment that needs diagnosis Run gencow deploy status --release-attempt <uuid> from the project; add --prod for the linked production app. Follow any linked deployment operation's retry gate. Status shows the attempt state, components, and deployment IDs; terminal attempt state alone does not authorize a replacement deploy
gencow env set, unset, or push stores the value but says runtime projection is pending or failed The cloud env catalog changed, but the running backend has not acknowledged that exact env revision Run the printed gencow env status --operation <id> command; do not repeat the mutation unless the status says retry is safe Status shows Runtime applied, or prints the failure class, correlation ID, retry precondition, and next action
App returns 503 APP_INFRA_UNAVAILABLE The managed runtime is temporarily unable to start or reach platform-managed infrastructure Retry after the suggested delay; if it persists, check gencow deploy status, review logs, and redeploy after platform status is healthy The response stays public-safe and does not include database URLs, tokens, or internal host details
Production static build points at localhost VITE_API_URL was missing at frontend build time Build with VITE_API_URL=https://<app>.gencow.app bun run build, then deploy static files Generated JS contains the deployed origin, not localhost
Custom domain SSL or routing fails DNS, apex/www policy, or active binding mismatch Follow Hosting & Custom Domains, check gencow domain status, use www CNAME for the simple path, and keep apex/www policy explicit https://www.example.com serves the intended app or redirects only by configured policy

Auth and API Base URL

Create one shared base URL and reuse it for auth lifecycle, queries, mutations, and realtime tickets.

// src/lib/gencow.ts
import { createAuthClient, createGencowClient } from "@gencow/client";
import { api } from "../gencow/api";

export const baseUrl = import.meta.env.VITE_API_URL ?? "http://localhost:5456";
export const auth = createAuthClient(baseUrl);
export const apiClient = createGencowClient({ api, baseUrl, auth });
// src/main.tsx
import { GencowProvider } from "@gencow/react";
import { apiClient } from "./lib/gencow";

root.render(
    <GencowProvider apiClient={apiClient}>
        <App />
    </GencowProvider>
);

Do not rely on createAuthClient() to auto-read VITE_API_URL. Passing the URL explicitly is the stable contract.

CRUD Lists

createCrud().list returns an object with the rows and metadata. Treat it like a paginated result even when you only need the first page.

import { useQuery } from "@gencow/react";
import { api } from "../gencow/api";

export function TaskList() {
    const { data: result, isLoading, error } = useQuery(api.tasks.list, {});

    if (isLoading) return <p>Loading...</p>;
    if (error) return <p>Could not load tasks.</p>;
    if (!result || result.data.length === 0) return <p>No tasks yet.</p>;

    return (
        <ul>
            {result.data.map((task) => (
                <li key={task.id}>{task.title}</li>
            ))}
        </ul>
    );
}

For paging, pass page and limit and disable navigation when there is nowhere to go.

const limit = 20;
const { data: result } = useQuery(api.tasks.list, { page, limit });
const totalPages = Math.max(1, Math.ceil((result?.total ?? 0) / limit));

Storage 403s

Hosted storage is private by default. A private object should not be shown to the browser through a long-lived bare URL.

export const listFiles = procedure.query
    .name("files.list")
    .handler(async ({ context: ctx }) => {
        const rows = await ctx.db.select().from(files);
        return Promise.all(
            rows.map(async (row) => ({
                id: row.id,
                name: row.name,
                previewUrl: (await ctx.storage.createReadGrant(row.storageId, {
                    ttlSeconds: 300,
                    disposition: "inline",
                })).url,
            }))
        );
    });

Use ctx.storage.getPublicUrl(storageId) only for assets that were stored with { visibility: "public" }.

AI Errors

Code or status Meaning User action
model_requires_upgrade / 402 The model is not available on the current plan Choose a lower-tier model or upgrade
provider_tpm_limited / provider_rpm_limited / 429 Provider admission is pacing the request Retry later, reduce request size, or upgrade capacity
403 Auth, plan entitlement, storage grant, or provider credential state blocked the request Check app auth, selected model, and whether private files use read grants
server_error Unexpected platform or provider failure Retry once, then check status/logs without exposing prompts or secrets

For cloud apps, use generated gencow/ai.ts or createGencowAI() helpers. Do not put provider SDK keys or raw provider clients in app code to work around errors.

Runtime 503s

APP_INFRA_UNAVAILABLE means the hosted runtime could not complete a platform-managed startup dependency and the platform considers the state retryable. Retry after the response delay, then check gencow deploy status and logs. If the app keeps returning the same code after platform status is healthy, redeploy with the latest CLI/runtime. Do not paste response bodies, logs, or screenshots that contain tokens, database URLs, storage grant URLs, or provider keys into public support channels.

CLI App Creation Errors

When gencow app create fails, the CLI exits unsuccessfully after printing the platform error. Preserve the Code and Correlation ID; they identify the exact request without exposing your login token. Run gencow app list before retrying so you do not create a duplicate after an uncertain network result.

If the message says App creation is temporarily unavailable, wait for platform recovery or contact support with only the safe error code, correlation ID, command time, CLI version, operating system, and runtime version. Do not send credential files, tokens, full environment dumps, or private deployment logs. A native runtime message printed after the platform error does not replace the first Code and Correlation ID as the support reference.

App creation itself does not start a runtime or allocate a tenant database. A runtime-capacity or deployment-executor issue should therefore appear during the first deployment, not as a partially created App. If an App exists but has not deployed successfully, it can still be deleted normally without requesting manual platform cleanup.

CLI Login Expired During Deploy

The CLI reports whether the rejected credential came from saved interactive login or an environment variable. For saved credentials, authenticate again against the same Platform:

npx gencow@latest login
npx gencow@latest whoami

If the message names GENCOW_TOKEN or GENCOW_DEPLOY_TOKEN, replace or unset that variable (or its CI secret) instead. Environment credentials override saved login credentials, so interactive login alone cannot replace an expired environment token. Never paste the token into a support request. If the CLI prints a correlation ID, share only that ID, the command time, Platform URL, CLI version, and operating system.

Deploy and Environment

Before deploying a frontend build, confirm the generated app talks to the intended backend:

VITE_API_URL=https://my-app.gencow.app bun run build
gencow deploy --static dist/

If auth works in development but not after static deploy, rebuild the frontend with the deployed VITE_API_URL and redeploy the static assets.

For cloud env changes, Stored means the encrypted catalog update succeeded. Runtime applied means a running backend acknowledged that exact revision. If the CLI prints an env operation ID, inspect it with:

gencow env status --operation envop_123