mastra-ai/mastra · error
Linear cursor is invalid.
Error message
Linear cursor is invalid.
What it means
For multi-project Linear sync the cursor is a JSON object mapping each source id to its last-seen cursor value. `decodeCursor` only parses JSON when there is more than one sourceId; if the stored cursor is not parseable JSON, is not a plain object (array, null, scalar), it throws 'Linear cursor is invalid.' This prevents restoring a resume position that would corrupt per-source bookmark tracking.
Source
Thrown at mastracode/factory/src/integrations/platform/linear/integration.ts:671
return { workspaceId: parsed.workspaceId, projectId: parsed.projectId };
} catch {
throw new Error('Linear project source id is invalid.');
}
}
function normalizeLabels(labels: string[] | undefined): string[] {
return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];
}
function decodeCursor(cursor: string | undefined, sourceIds: string[]): Record<string, string | null | undefined> {
if (!cursor) return {};
if (sourceIds.length === 1) return { [sourceIds[0]!]: cursor };
try {
const parsed = JSON.parse(cursor) as unknown;
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error();
return parsed as Record<string, string | null>;
} catch {
throw new Error('Linear cursor is invalid.');
}
}
function encodeCursor(state: Record<string, string | null>, sourceIds: string[]): string {
if (sourceIds.length === 1) return state[sourceIds[0]!]!;
return JSON.stringify(state);
}
function requireLinearConnection(connection: IntegrationConnection): void {
if (connection.type !== 'oauth') {
throw new Error('Linear capabilities require an OAuth connection.');
}
}
function isNotFound(error: unknown): boolean {
return error instanceof PlatformApiError && error.status === 404;
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Start the multi-source sync with no cursor (undefined/null) so it builds a fresh object-shaped cursor.
- Convert legacy single cursors: wrap them as `{ [sourceId]: legacyCursor }` before passing.
- Ensure whatever persists the cursor does not truncate the JSON string.
- Catch this error and fall back to a full re-sync from a null cursor.
Example fix
// before
await integration.pull({ sourceIds: [idA, idB], cursor: savedSingleCursor });
// after
const parsed = savedSingleCursor?.startsWith('{') ? savedSingleCursor : JSON.stringify({ [idA]: savedSingleCursor });
await integration.pull({ sourceIds: [idA, idB], cursor: parsed }); Defensive patterns
Strategy: fallback
Validate before calling
function safeDecodeCursor(cursor: string | undefined, sourceIds: string[]): Record<string, string | null> {
if (!cursor || sourceIds.length === 1) return {};
try {
const p: unknown = JSON.parse(cursor);
if (p && typeof p === 'object' && !Array.isArray(p)) return p as Record<string, string | null>;
} catch { /* fall through */ }
return {}; // invalid cursor => fresh sync
} Type guard
function isCursorMap(v: unknown): v is Record<string, string | null> {
return v !== null && typeof v === 'object' && !Array.isArray(v) &&
Object.values(v).every(x => typeof x === 'string' || x === null);
} Try / catch
try {
await sync({ cursor: savedCursor });
} catch (err) {
if (err instanceof Error && err.message === 'Linear cursor is invalid.') {
await sync({ cursor: undefined }); // full re-sync
} else throw err;
} Prevention
- Migrate single-source cursors to `{ [sourceId]: cursor }` when adding more projects.
- Wrap the stored cursor in a versioned envelope so shape changes are detectable.
- On decode failure, prefer a null-cursor full re-sync over retrying the bad value.
When it happens
Trigger: Calling pull/sync with multiple sourceIds and a cursor string that is not a JSON object — e.g. a single-source raw cursor string, 'null', '"text"', '[1,2]', or truncated JSON from storage.
Common situations: A sync that started with one project (cursor saved as a bare string) later expanded to multiple projects; cursor field shrunk/truncated by a DB migration; operator pasting a single-source cursor into a multi-project job.
Related errors
- Linear project source id is invalid.
- Failed to parse A2A stream event: ${error instanceof Error ?
- ${EXTRACTED_VALUES_TAG} must contain a JSON object.
- Failed to parse working memory input as JSON: ${errorMessage
- Invalid filter format: ${error instanceof Error ? error.mess
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2cfdf44ce4821c8b.
Report an issue: GitHub.