google-gemini/gemini-cli · error · Error
Task ${taskId} is missing persisted state in metadata.
Error message
Task ${taskId} is missing persisted state in metadata. What it means
Thrown by GCSTaskStore.save() when the task being persisted has no valid __persistedState entry in its metadata. The persisted state (stored under the METADATA_KEY '__persistedState') must contain an _agentSettings object (with kind === 'state_agent_settings' and a string workspacePath) and a _taskState field. Without it, the GCS store has nothing durable to write.
Source
Thrown at packages/a2a-server/src/persistence/gcs.ts:103
}
private getObjectPath(taskId: string, type: ObjectType): string {
if (!isTaskIdValid(taskId)) {
throw new Error(`Invalid taskId: ${taskId}`);
}
return `tasks/${taskId}/${type}.tar.gz`;
}
async save(task: SDKTask): Promise<void> {
await this.ensureBucketInitialized();
const taskId = task.id;
const persistedState = getPersistedState(
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
task.metadata as PersistedTaskMetadata,
);
if (!persistedState) {
throw new Error(`Task ${taskId} is missing persisted state in metadata.`);
}
const workDir = process.cwd();
const metadataObjectPath = this.getObjectPath(taskId, 'metadata');
const workspaceObjectPath = this.getObjectPath(taskId, 'workspace');
const dataToStore = task.metadata;
try {
const jsonString = JSON.stringify(dataToStore);
const compressedMetadata = gzipSync(Buffer.from(jsonString));
const metadataFile = this.storage
.bucket(this.bucketName)
.file(metadataObjectPath);
await metadataFile.save(compressedMetadata, {
contentType: 'application/gzip',
});
logger.info(View on GitHub (pinned to 5024443c72)
Solutions
- Ensure the task metadata is populated via setPersistedState(metadata, { _agentSettings, _taskState }) before calling save.
- Before calling save, verify getPersistedState(task.metadata) returns a non-undefined value.
- Confirm _agentSettings has kind === 'state_agent_settings' and a string workspacePath, and _taskState is present.
Example fix
// before
const task: SDKTask = { id, metadata: {}, ... };
await store.save(task); // throws
// after
import { setPersistedState } from '../types.js';
const task: SDKTask = {
id,
metadata: setPersistedState({}, {
_agentSettings: { kind: 'state_agent_settings', workspacePath: '/work', ... },
_taskState: 'submitted',
}),
...,
};
await store.save(task); Defensive patterns
Strategy: validation
Validate before calling
import { getPersistedState } from '../types.js';
function canSaveTask(task: SDKTask): boolean {
return getPersistedState(task.metadata as PersistedTaskMetadata) !== undefined;
}
// Before save:
if (!canSaveTask(task)) {
task.metadata = setPersistedState(task.metadata, {
_agentSettings: agentSettings,
_taskState: currentState,
});
}
await store.save(task); Type guard
import { isPersistedStateMetadata, METADATA_KEY } from '../types.js';
function hasValidPersistedState(metadata: unknown): boolean {
return (
typeof metadata === 'object' &&
metadata !== null &&
METADATA_KEY in metadata &&
isPersistedStateMetadata((metadata as Record<string, unknown>)[METADATA_KEY])
);
} Try / catch
try {
await store.save(task);
} catch (e) {
if (e instanceof Error && e.message.includes('missing persisted state')) {
// Repopulate and retry, or log and skip
task.metadata = setPersistedState(task.metadata, state);
await store.save(task);
} else {
throw e;
}
} Prevention
- Always create task metadata through the agent executor which calls setPersistedState().
- Add a unit test asserting getPersistedState(task.metadata) is non-undefined before any save call.
- Never construct a Task object with an empty or partial metadata object intended for persistence.
When it happens
Trigger: Calling store.save(task) where task.metadata lacks the '__persistedState' key, or where the nested _agentSettings or _taskState are missing/malformed. This occurs when a task is constructed manually instead of through the agent executor that calls setPersistedState().
Common situations: Manually building an SDK Task object without populating persisted state; migrating from an older metadata format that didn't use __persistedState; a bug in the executor (executor.ts) that skips the setPersistedState() call before delegating to save.
Related errors
- Loaded metadata for task ${taskId} is missing internal persi
- Cannot reconstruct task ${sdkTask.id}: missing persisted sta
- GCS bucket name is required.
- Failed to create GCS bucket ${this.bucketName}: ${createErro
- Failed to initialize GCS bucket ${this.bucketName}: ${error}
AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12).
Data as JSON: /api/errors/7735d847dbd561e4.
Report an issue: GitHub.