Troubleshooting

Fix common SDK issues.

Identify the issue and find the right fix.

Check your setup

Check: Run these checks to inspect the installation, platform, and configured models.

let primordial = PrimordialClient()
let integration = try primordial.integrationStatus()
let status = await primordial.ai.status()

print(integration.sdkVersion, integration.platform, integration.isSimulator)
print(status.generation, status.embedding, status.speech)

Fix: Find the matching problem below and follow its solution.

import Primordial fails

Check: Confirm that the app target links the Primordial product.

Fix: Remove duplicate package entries, choose File > Packages > Reset Package Caches, then add the package once using Getting Started.

The project compiles but AI execution fails

Check: Confirm these requirements:

  • Xcode 26.0 or later and Swift 6.2 or later.
  • iOS 26.0 or later, or macOS 26.0 or later.
  • A supported physical iOS device or Mac for downloadable local models, embeddings, and speech.

Fix: Run downloadable models, embeddings, and speech on a supported physical iOS device or Mac. Use the simulator only for installation and import checks.

Activation is required or rejected

Check: Print the activation error and confirm the evaluation key and bundle identifier.

do {
    try await primordial.activate(.evaluationKey("pk_eval_..."))
} catch let error as PrimordialActivationError {
    print(error.localizedDescription)
}

Fix: Follow the matching error:

  • evaluationKeyInvalid, evaluationKeyRevoked, or evaluationKeyExpired: rotate or replace the key.
  • unregisteredAppIdentifier: register the exact, case-sensitive bundle identifier.
  • activationMetadataMissing: confirm the target has a bundle identifier and supported platform metadata.
  • activationRequestFailed: check connectivity and try again without logging the key.

See Evaluation Keys for setup instructions.

A required capability is unavailable

Check: Inspect the workflow status and required storage.

let requirement = await primordial.ai.status(for: .answering)

print(requirement.downloadBytes)
print(requirement.requiredAvailableBytes)

Fix: Ask for download consent, then call makeAvailable for the required workflow.

for try await progress in primordial.ai.makeAvailable(.answering) {
    print(progress.phase, progress.fractionCompleted ?? 0)
}

Installation fails storage or verification

Check: Inspect the reported error and available storage.

do {
    for try await _ in primordial.ai.makeAvailable(.generation) { }
} catch PrimordialAIError.insufficientStorage(let requirement) {
    print(requirement.requiredAvailableBytes)
    print(requirement.availableBytes)
}

Fix: Follow the matching error:

  • downloadFailed: check connectivity and call makeAvailable again.
  • verificationFailed: retry once; incomplete files are never marked installed.
  • corruptedStorage: wait for active work to finish, remove the affected managed download through its matching advanced resource, then reinstall it.
try await primordial.advanced.generation.removeDownload()
for try await _ in primordial.ai.makeAvailable(.generation) { }

Use advanced.embedding or advanced.speech when those downloads are affected.

An installation was cancelled

Check: Confirm the task ended with CancellationError.

Fix: Ask for consent and call makeAvailable again. Primordial reuses completed downloads.

Background downloads do not finalize on iOS

Check: Confirm that the iOS app delegate forwards background download events.

func application(
    _ application: UIApplication,
    handleEventsForBackgroundURLSession identifier: String,
    completionHandler: @escaping () -> Void
) {
    _ = PrimordialClient.handleEventsForBackgroundURLSession(
        identifier: identifier,
        completionHandler: completionHandler
    )
}

Fix: Add the handler above. After relaunch, call the same makeAvailable capability again. A user force-quit cancels the transfer.

The Apple system model is unavailable

Check: Inspect why the system model is unavailable.

let status = await primordial.ai.status()

if case .systemUnavailable(_, let reason, let fallback) = status.generation {
    showUnavailable(reason, fallback: fallback)
}

Fix: Follow the matching reason:

  • deviceNotEligible: hide the feature or offer an application-supported alternative.
  • appleIntelligenceNotEnabled: explain that the person must enable Apple Intelligence in Settings. Apps cannot enable it.
  • modelNotReady: ask the person to try later while the system prepares its model.
  • unsupportedLocale: select a supported language or offer another experience.

To offer another model, configure it explicitly in AI Model Setup.

Generation or structured output fails

Check: Match the error to the cause below.

Fix: Follow the matching error:

  • contextWindowExceeded: shorten the input, retrieved context, or conversation history and retry.
  • invalidQuery: remove empty input and correct invalid limits, categories, fields, or weights.
  • structuredOutputInvalid: try again or use a simpler schema.
  • unsupportedFeature: inspect ai.capabilities() and choose a workflow supported by the configured model.
  • generationFailed: retry when appropriate and discard partial output.

Collection indexing or search fails

Check: Confirm the data, query, and installed capabilities:

  • Keep the PrimordialClient identifier stable for the same account or workspace.
  • Use nonempty collection names, record IDs, and fields; only text fields are embedded.
  • Keep one value type per field name throughout a collection.
  • Use nonempty queries, positive limits and field weights, and filters compatible with stored field types.
  • Install .semanticSearch before synchronization, reindexing, or text search.

Fix: Correct invalid data or queries. If the index is incompatible, rebuild it:

for try await progress in notes.reindex() {
    print(progress.phase, progress.fractionCompleted)
}

See Store & Search for collection requirements.

Collection synchronization fails

Check: Inspect the collection status and the typed error.

let status = try await notes.synchronizationStatus()

print(status.sourceIdentifier)
print(status.sourceSchemaVersion)
print(status.hasCheckpoint)
print(status.requiresSnapshot)

Fix: Follow the matching condition:

  • sourceMismatch: use the source identifier already bound to the collection, or call reset() before intentionally binding a different source.
  • sourceSchemaMismatch: use .automatic or .snapshot to build a complete snapshot after a deliberate source schema change.
  • checkpointRequired: run .automatic or .snapshot before requesting .incremental synchronization.
  • checkpointExpired or invalidCheckpoint: run .automatic to fall back to a complete snapshot, or explicitly request .snapshot.
  • invalidSynchronizationOptions: choose a batch size from 1...1000.
  • Cancellation: call synchronize(from:) again. Completed checkpoints are reused and an incomplete replacement is not exposed to search.
for try await _ in notes.synchronize(
    from: source,
    options: .init(mode: .automatic)
) { }

reset() removes the collection's searchable records, checkpoint, and source binding. Use it only when you intend to clear and rebind the collection.

SwiftData changes or removals are missing

Check: Confirm the SwiftData source requirements:

  • The source uses the same ModelContainer as the application data.
  • The encoded record ID is stable, nonempty, and unique.
  • The fetch descriptor does not contain a predicate.
  • The record ID preserves its value when the model is deleted.

Fix: Add .preserveValueOnDeletion to the stable record ID and synchronize again.

@Model
final class Note {
    @Attribute(.unique, .preserveValueOnDeletion)
    var id: UUID

    var body: String
}

Filtered SwiftData sources are not supported. Map the complete model type into a collection, then use typed collection filters when searching.

See Synchronize SwiftData for the complete setup.

Recording or transcription fails

Check: Confirm the application target includes:

  • NSMicrophoneUsageDescription
  • NSSpeechRecognitionUsageDescription
  • For a sandboxed macOS app, enable Audio Input under App Sandbox.

Fix: Add the missing permissions, enable Audio Input for sandboxed macOS apps, and install .voiceInput. After stop() or cancel(), create a new recording session. See Speech.