stablyai/orca · error

Artifact share records could not be read safely.

Error message

Artifact share records could not be read safely.

What it means

Thrown by the share-record store reader when JSON.parse(readFileSync(recordPath)) fails — the share-record JSON file exists but its content is unparseable. The original error is attached as `cause`. This is the read-level counterpart to the format check at 753 and only signals JSON corruption, not a schema mismatch.

Source

Thrown at src/main/artifacts/artifact-share-record-store.ts:116

    changed: retained.length !== currentEntries.length
  }
}

function readRecords(
  profileId: string,
  userDataPath: string,
  preserveExpired?: { sourceKey: string; slug: string; editToken: string },
  pruneExpired = true
): ArtifactShareRecordFile {
  const path = recordPath(profileId, userDataPath)
  if (!existsSync(path)) {
    return { version: 2, lifecycleGeneration: 0, lifecycleNonce: '', shares: {} }
  }
  let parsed: ParsedArtifactShareRecordFile
  try {
    parsed = JSON.parse(readFileSync(path, 'utf8')) as ParsedArtifactShareRecordFile
  } catch (error) {
    throw new Error('Artifact share records could not be read safely.', { cause: error })
  }
  if (parsed.version === 1) {
    return { version: 2, lifecycleGeneration: 0, lifecycleNonce: '', shares: {} }
  }
  if (
    parsed.version !== 2 ||
    !parsed.shares ||
    typeof parsed.shares !== 'object' ||
    Array.isArray(parsed.shares)
  ) {
    throw new Error('Artifact share records have an unsupported format.')
  }
  const shareEntries = Object.entries(parsed.shares as Record<string, unknown>)
  const validShares = Object.fromEntries(
    shareEntries.filter((entry): entry is [string, ArtifactShareRecord] => isRecord(entry[1]))
  )
  const pruned = pruneExpired
    ? pruneRecords(validShares, Date.now(), preserveExpired)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Read error.cause for the JSON parse offset and inspect the file around that byte.
  2. If unrecoverable, back up then delete the share-record file — a fresh empty store ({version:2,...}) will be recreated on next access; re-share artifacts as needed.
  3. Ensure the writer uses atomic write-temp-then-rename so concurrent writes/crashes cannot corrupt the file.

Example fix

// before
const records = readShareRecords(...) // JSON.parse throws

// after
try { return readShareRecords(...) }
catch (e) {
  if (e.cause instanceof SyntaxError) await restoreFromBackupOrReset(profileId, userDataPath)
  throw
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { readFileSync } from 'node:fs'

function isShareRecordJsonParseable(path: string): boolean {
  try { JSON.parse(readFileSync(path, 'utf8')); return true } catch { return false }
}

if (existsSync(path) && !isShareRecordJsonParseable(path)) {
  await fs.promises.rename(path, `${path}.corrupt`)
}

Type guard

function isJsonParseError(e: unknown): boolean {
  return e instanceof SyntaxError || (e instanceof Error && e.cause instanceof SyntaxError)
}

Try / catch

try {
  return readShareRecords(profileId, userDataPath)
} catch (e) {
  if (isJsonParseError(e)) {
    await backupAndResetShareRecords(profileId, userDataPath)
    return { version: 2, lifecycleGeneration: 0, lifecycleNonce: '', shares: {} }
  }
  throw e
}

Prevention

When it happens

Trigger: A partial write left truncated JSON in the share-record file; encoding/BOM mangling; a non-JSON file overwritten the record path; the process was killed mid-write before the file was complete.

Common situations: Power loss during a share-record update (non-atomic write); a sync/backup tool rewrote the file with conflicts; a hand-edit introduced a syntax error; antivirus quarantined then restored a partial file.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/fddf84387eddd79c. Report an issue: GitHub.