Ir al contenido

Resolución de problemas

not available (403) o (404). La función está apagada en ese repositorio, o el token no la ve. Dependabot, code scanning, las discusiones y el grafo de dependencias responden así cuando están desactivados. El colector anota el hecho y sigue: un repositorio con una función apagada no debe detener la pasada de los otros cuarenta.

Si son todos los repositorios y no uno, es el token. El tráfico necesita acceso de escritura y, en un token fine-grained, el permiso de repositorio Administration (lectura); las alertas necesitan security_events. Ver el token.

Una función encendida y nada recogido de ella. Code scanning activado esta mañana, Dependabot encendido, un foro abierto: el colector preguntó antes de que lo hicieras, le dijeron que no, y recuerda ese rechazo un día en vez de pagarlo en cada pasada. Se nota como muy tarde al día siguiente, también tras un reinicio; borrar el fichero de caché junto al fichero de estado vuelve a preguntar en el acto. Ver un rechazo también se recuerda.

still being computed by GitHub (202). GitHub calcula los endpoints stats/* de forma asíncrona y responde 202 con cuerpo vacío mientras trabaja. La siguiente pasada suele conseguir los números.

Dos de ellos no lo hacen nunca. En una cuenta personal stats/code_frequency y stats/contributors devuelven 202 con cuerpo vacío indefinidamente, que es por lo que este proyecto no los llama: las líneas añadidas y quitadas salen del colector de commits.

pagination is limited for this resource (422). El final de un feed de actividad, no un fallo. GitHub sirve tres páginas del feed de eventos y rechaza la cuarta.

Un repositorio sin tráfico mostrando una ventana que terminó hace semanas. GitHub sigue devolviendo los últimos catorce días que tuvieron datos, no los últimos catorce días. El colector anota lo que le dicen.

cache file not read, the first pass of each family pays in full. El fichero de caché que hay junto al fichero de estado quedó cortado, dañado o escrito en otro formato, así que no se lee en absoluto, y el siguiente guardado lo sobrescribe. Cuesta una pasada de cada familia a precio completo y no pierde nada; ver la caché que hay a su lado.

which repositories moved could not be asked, reading those it did not answer for. La consulta que dice a commits, issues e issueevents qué repositorios leer falló, o respondió por algunos de ellos. Cada repositorio del que no dijo nada se lee como si no se hubiera preguntado, así que no se pierde nada y la pasada cuesta lo que costaba antes de que existiera la consulta; ver preguntar primero qué se movió.

outbound search read fewer items than it counts, GitHub serves a thousand at most. GitHub sirve mil resultados de una búsqueda y ni uno más, y la cuenta tiene más que eso en uno de los estados que busca outbound, las pull requests fusionadas por ejemplo. Se quedan los mil que se movieron más recientemente, y la línea se dice una vez por recuento; ver qué alcanza que una pasada no.

NOTICE: column ... already exists, skipping de psql. Reproducir el fichero del destino SQL en una base de datos que ya tiene sus tablas. El fichero declara cada tabla y cada columna de campo que escribe, porque no puede preguntar cuáles existen, y PostgreSQL lo dice por cada una que ya está, con un relation ... already exists para la tabla. No ha fallado nada.

Una familia que no aparece nunca en el log. Aún no le toca. Con una cadencia de doce horas, medio día de logs puede legítimamente no mencionar nunca stats. Una familia de seis horas o más también puede tocarle y estar esperando su turno detrás de otra, y el log la nombra bajo waiting en slow families due together take turns; ver las familias lentas se turnan.

github.token is empty and GITHUB_TOKEN is unset. Exactamente lo que dice.

every.families.<name>: unknown collector. El nombre no es una familia. El mensaje lista las treinta y cuatro que existen, en un paréntesis tras los dos puntos.

groups: is empty. groups: [] no recogería absolutamente nada. Omite la clave para recogerlo todo, que es lo que significa cuando no está.

groups[N]: "<name>" is not a group. El nombre no es un grupo. El mensaje lista los que existen, y ghchronicle -groups imprime cada uno con sus familias.

groups[N]: "<name>" is a family, not a group. Familias y grupos son sustantivos en minúscula de la misma tabla, así que este es fácil de encontrar. El mensaje nombra el grupo en el que está la familia, que probablemente es lo que querías, y apunta a every.families.<name>, que es donde vive la cadencia de una sola familia.

sinks: enable at least one of .... Una ejecución que recoge y tira es casi nunca lo que alguien quiso. -card-only es la excepción y no necesita ningún destino.

prometheus exporter: listen tcp :9605: bind: address already in use. Se informa al arrancar en vez de quedar sepultado en una goroutine, para que un choque de puerto no te deje con un colector corriendo y un exportador ausente en silencio.

influx write: 400. Casi siempre una colisión de tipo de columna. InfluxDB fija una columna como etiqueta o como campo la primera vez que la ve y rechaza las escrituras posteriores que no coincidan. Si un colector cambió de qué tipo es un nombre, hay que borrar la tabla: DELETE /api/v3/configure/table.

family failed everywhere, not marking it as run. Fallaron todos los repositorios en una familia, así que se reintentará en vez de darse por hecha. Que falle un repositorio es normal; que fallen todos es el token, la red o una caída.

collector failed que nombra un 500, un 502 Bad Gateway, un 503 o un 504 Gateway Timeout. GitHub no terminó la respuesta a una petición, en su pasarela o en la aplicación, o no la terminó el almacenamiento del que se lee el log de un job. El cliente pregunta una vez más dos segundos después y no dice nada de ello, así que una línea como esta es una petición que falló dos veces, y la siguiente pasada vuelve a preguntar. Una consulta GraphQL se vuelve a preguntar del mismo modo, salvo por una respuesta: un 502 o un 504 que tardó los diez segundos de GitHub en volver es una consulta demasiado grande, que los colectores que tienen una página más pequeña vuelven a preguntar con ella. Una línea que dice que la consulta es demasiado grande para una sola petición es una que agotó el tiempo incluso con la página más pequeña, o en un recorrido sin página más pequeña que pedir. Lo leído antes se escribe, un relleno no anota ese repositorio como recorrido, y la pasada siguiente lo vuelve a leer.

state not saved o cache file not saved. El usuario con el que corre el colector no pudo poner el fichero en su sitio. Cada uno de los dos se escribe con un nombre temporal en el directorio que nombra el fichero de estado y después se renombra a su sitio, así que o no se puede escribir en ese directorio, o no existe y no se puede crear, o el propio fichero no se puede sustituir con un renombrado. Nada de lo que aprende una pasada sobrevive entonces a un reinicio: el siguiente arranque recoge todas las familias y vuelve a recorrer la lista de estrellas, el historial entero de estrellas y las pull requests en coautoría. En un contenedor es un directorio del anfitrión montado sin entregárselo al uid 65532, un volumen nuevo montado en otro sitio que no sea /var/lib/ghchronicle, o cualquier volumen nuevo con una imagen anterior a la 2.6.1, ninguno de ellos de ese uid, o un fichero de estado montado solo, sobre el que no se puede renombrar; ver qué tiene que ser escribible.

the state file ... cannot be read o does not parse, y la ejecución se detiene. El fichero de estado está ahí y esta ejecución no pudo leerlo, o no está entero. Una ejecución que escribe en los almacenes no lo toma por uno nuevo, lo que olvidaría las relecturas que una migración aún debe y pondría un fichero nuevo en su lugar en su primer guardado. Un fichero que dejó root, tras un -migrate -yes o un relleno lanzado con sudo, es la causa habitual: devuélveselo con chown al usuario con el que corre el colector. Si se aparta en su lugar, la siguiente ejecución empieza con uno nuevo, y lo que registraba, entre ello una relectura aún debida, se pierde; ver el fichero de estado.

rate limit reserve reached, family skipped. Una vez está bien. En cada pasada significa que las cadencias son demasiado rápidas para el número de repositorios. Si el cubo que se queda corto es core, alarga artifacts y después actions; si es graphql, issues, issueevents y commits. Ver qué crece con la actividad, no con el tamaño.

refill owed: a store a migration cleared does not hold that history yet. Una migración despejó la medida que se nombra en ese almacén y volver a leer su historial de GitHub no terminó: se paró la ejecución, un almacén rechazó una escritura o GitHub no respondió. Ahora el almacén parece uno que nunca guardó la forma antigua, así que solo lo sabe el fichero de estado. Bajo migrate: warn un arranque lo dice y hace su pasada; -migrate -yes, que la línea nombra, lo vuelve a leer desde donde se paró, y también cualquier arranque bajo migrate: auto. Ver volver a leer el historial.

reconciled en WARN, con not_served. Tras volver a leer una medida despejada, ghchronicle comparó la copia de las filas antiguas con la tabla y encontró elementos que GitHub ya no sirve: un repositorio borrado o que ya no se cubre, un comentario borrado, una alerta cuya función se apagó. first nombra unos pocos, y only_in es la copia que aún los guarda, hasta que se purga: un día después de la migración las de PostgreSQL y Elasticsearch, y cuando diga el calendario del servidor la de InfluxDB 3, 72 horas por omisión, o nunca en un servidor anterior a la 3.2. Traspasarlos se hace a mano, desde esa copia, mientras está.

Un número es múltiplo del número de pasadas. Algo que es una instantánea se está sumando en el tiempo. Los referrers, las rutas, las etiquetas y los hitos son instantáneas de una ventana sin fecha propia; se sellan al inicio del día UTC para que las pasadas de un día reescriban una fila, y el dashboard toma la más reciente y no la suma.

La mediana de tiempo hasta la revisión de otra persona dice No data. El panel lee seconds_to_first_human_review, que deja fuera a los bots de revisión y las respuestas del propio autor; en una cuenta donde nadie más revisa, ninguna pull request lo lleva y la tarjeta está honestamente vacía. No significa que no se haya revisado nada. La velocidad de los bots está en la tabla Reviewers, donde cada uno va marcado como bot: medido, nueve de cada diez pull requests tuvieron una revisión de un bot en menos de un minuto.

Los clones son enormes comparados con las visitas. La integración continua clona un repositorio miles de veces por cada visita humana. Un repositorio medido aquí tuvo más de cien clones por cada visita. clones no cuenta personas.

open_issues no cuadra con el número de issues. Ese campo es de GitHub, y GitHub cuenta las pull requests como issues dentro. La medida gh_issue es la que cuenta issues.

El almacenamiento de artefactos parece pequeño. Compara walked con count en gh_artifact_total. Cuando no coinciden, el tamaño vivo es un suelo: el repositorio tiene más artefactos de los que recorrió el tope de páginas, o una página del listado falló en esa pasada y la fila se escribió con las páginas anteriores. También puede salir más pequeño de lo esperado por una segunda razón: count es el total de GitHub e incluye los artefactos que ya ha caducado, mientras que el tamaño es solo sobre los vivos, que son los que cuenta live_count.

Un panel responde con un error de esquema en vez de decir No data. InfluxDB 3 crea una columna la primera vez que una fila la trae, así que una consulta que nombra una que ninguna fila ha escrito falla al planificarse. Una versión que añade un campo le hace eso a una base ya existente hasta que la familia que lo escribe hace una pasada: gh_fork.seconds_to_push y gh_artifact_total.live_count fueron dos, que nombran los paneles Forks y “Artifact storage counted”, y la familia forks corre cada doce horas. Una versión que añade una medida con la que un panel hace un join le hace lo mismo al panel entero, también en PostgreSQL, donde lo que falta es la tabla y no la columna: la tabla “Work elsewhere” hace un join con gh_upstream_repo para las estrellas de cada repositorio, y hasta que la primera pasada de outbound de la versión nueva la escribe, que es dentro de una hora, los dos almacenes rechazan la tabla en vez de dejar vacía su columna Stars. Espera esa pasada o publica los dashboards después. Un -once no la adelanta: corre solo las familias a las que les toca, y a outbound no le toca hasta una hora después de su última pasada. Las demás columnas que pueden faltar están en Columnas que solo existen una vez escritas.

La gráfica de tráfico solo llega catorce días atrás. Eso es una primera pasada. La ventana se reescribe día a día en cada pasada, así que la serie se extiende conforme el colector sigue corriendo. No se puede rellenar: GitHub nunca guardó nada más viejo.

Un panel dice “Query would scan 10000 Parquet files”. InfluxDB 3 Core escribe un fichero por partición y por petición de escritura, y no los compacta nunca, así que un almacén alimentado por una versión de esta herramienta anterior al registro de escrituras guarda sus filas en muchos más ficheros de los que necesita. Ensanchar el intervalo del panel no ayuda: el límite cuenta los ficheros que abre el planificador, antes de cualquier agregación. Lo que ayuda es el registro, que viene encendido y detiene el crecimiento, y después una de tres cosas para lo ya acumulado: subir --query-file-limit en el servidor, reescribir las tablas afectadas, o pasar a InfluxDB 3 Enterprise, que compacta por su cuenta y es gratis para uso doméstico. Ver solo se escribe lo que ha cambiado.

Un panel de Prometheus muestra una línea plana. Eso es el almacén, no los datos. El exportador sirve valores actuales, así que la ventana de tráfico de catorce días se colapsa a su día más reciente y la historia de estrellas al total actual. Ver la fecha del punto.

Ejecuta una pasada en primer plano y lee lo que dice. Después comprueba, en orden:

  1. que -list imprime los repositorios que esperas,
  2. que el log de la pasada dice written,
  3. que el destino es alcanzable.
Ventana de terminal
ghchronicle -config config.yaml -list # los repositorios, y cuáles quedan aparte
ghchronicle -config config.yaml -once # una pasada en primer plano, y salir
journalctl -u ghchronicle -f # bajo systemd

debug añade esto a eso y nada más: el tamaño del libro de escrituras al arrancar, un primer arranque sin fichero de caché, un arranque que vuelve a listar jobs porque un almacén no lleva registro, las familias de cuenta saltadas por falta de targets.user, las entradas que un destino dejó fuera por viejas, una pasada solo de tarjeta que deja en paz el fichero de estado, cada guardado del fichero de caché, las migraciones que un arranque encuentra innecesarias o ya aplicadas, las anotadas o congeladas que el primer arranque dijo en INFO, y cada copia que apartó una migración y que el fichero de estado olvida porque el almacén la purga o la guarda para siempre. No hay registro por petición en ningún nivel. Ver depuración.

log:
level: debug

Una familia a la que aún no le toca sencillamente no aparece.

Busca la línea de depuración que las cuenta. Loki rechaza una entrada que esté más atrasada que su ventana de desorden respecto a la entrada más nueva que ya hay en ese stream, la mitad del max_chunk_age del ingester y así una hora por omisión, así que el destino deja fuera las más viejas en vez de perder el envío entero. Sube max_age solo junto al propio max_chunk_age de Loki. Ver Loki.

Permissions needed: datasources:create. El token publica dashboards y no puede crear datasources. Un Editor puede lo primero y no lo segundo, así que dale ese permiso a la cuenta de servicio, hazla Admin, o deja que adopte un datasource creado por ti nombrándolo en grafana.datasource.uid, que solo lee. Corregir un datasource que ya está pide datasources:write en su lugar, con las mismas salidas. Eso detiene la ejecución para el datasource del almacén, que leen todos los paneles. Para el de Loki es solo un aviso, más abajo.

datasource ... does not answer: connection refused. Grafana llegó a la dirección y no había nadie escuchando, que casi siempre significa que la dirección es la buena para el colector y la mala para Grafana. Un colector en el anfitrión escribe a un puerto publicado; Grafana en un contenedor llega al mismo almacén por su nombre en la red de contenedores, y 127.0.0.1 allí es el contenedor. Pon en grafana.datasource.url la dirección que usaría Grafana. La ejecución se niega en vez de publicar, porque un dashboard contra un datasource inalcanzable no dibuja nada y no dice por qué.

asking datasource ... whether it answers: ... datasources:query. El token no puede consultar el datasource, que no es lo mismo que un datasource que no llega a su almacén, y la dirección no es lo que hay que cambiar. Medido en Grafana 13, una cuenta de servicio sin rol recibe esto y un Editor no, así que dale el rol de Editor.

Invalid API key. El token llegó a Grafana como los caracteres ${GRAFANA_TOKEN} y no como un token, lo que significa que la variable no está donde corre el colector. En una unidad de systemd eso es un EnvironmentFile que la unidad no lee, o una variable nombrada en el fichero y no exportada.

El datasource está y no tiene contraseña. Solo se envía una contraseña que escriba el propio DSN. Una que pgx encontrara en PGPASSWORD o en un .pgpass de la máquina que publicó se nombra en una línea y se queda ahí, porque un Grafana es compartido y una credencial que la configuración nunca mencionó no es cosa de copiar dentro.

the dsn asks for sslmode=prefer and Grafana's datasource has no such mode. Lo que hace libpq por omisión es intentar TLS y seguir sin él, y el datasource o exige o rechaza. Se le puso disable; pon grafana.datasource.sslmode en require, verify-ca o verify-full si eso no encaja con tu servidor.

Dos dashboards, y el que miras deja de cambiar. El generado tiene su propio uid y cada publicación lo sobreescribe, así que esto solo pasa cuando el tuyo vive en otro sitio: importado como nuevo, o renombrado a mano. Nombra el que lees en grafana.dashboard_uid.

... is still in Grafana and no ... sink is configured here. Algo que esto creó está bajo un uid al que ya nadie escribe, que es lo que deja atrás cambiar de almacén. Es un aviso y no se tocó nada; bórralo en Grafana cuando hayas terminado con él.

no sink this builds a dashboard for is configured. Hay dashboards para cinco almacenes y el sink que tienes no es uno de ellos. Un sink que reenvía no tiene dashboard propio porque el dashboard pertenece al destino, y file, stdout y loki no son almacenes de métricas.

warning: the Loki datasource ghchronicle-loki could not be set up. El token no puede crear el datasource de Loki del que lee el panel de la salida del trabajo fallido, y la línea nombra el permiso que le falta: datasources:create para un Editor, porque el datasource aún no está. Nada más espera por él: ese único panel queda como la nota que llevan los ficheros exportados, y los dashboards se publican siempre que se pueda el datasource del propio almacén. Nombra en grafana.datasource.loki_uid un datasource de Loki que Grafana ya tenga, o concede el permiso. La línea enumera los datasources de Loki que tiene Grafana, con sus direcciones, porque el que hay que nombrar suele estar ya ahí bajo una dirección a la que el colector no envía, como el nombre de Loki en la red de contenedores de Grafana. La 2.4.0 y la 2.5.0 detenían aquí toda la publicación, con the Loki datasource: writing datasource ghchronicle-loki, y loki_uid también lo arregla en ellas.

warning: the Loki datasource ghchronicle-loki is used as Grafana has it. Lo creó una ejecución anterior con un token que podía escribir datasources, y este token no puede reescribirlo: la línea nombra datasources:write. Un sink con tenant_id pide esa reescritura en cada arranque, porque el tenant es un secreto que Grafana nunca devuelve para comparar, y también la pide un datasource cuya dirección se cambió a mano. El panel lo lee tal cual, así que no se pierde nada salvo que el sink se haya movido desde entonces. Concede al token datasources:write para mantener su dirección y su tenant al día con el sink, o pon grafana.datasource.loki_uid en ghchronicle-loki para leerlo sin intentarlo.

datasource ... (loki) adopted. Grafana ya tenía un datasource de Loki en la dirección de la que sale el extremo de envío del sink, así que el panel lee ese y no se creó un segundo. Adoptar solo lee, así que un token que no puede crear datasources llega hasta aquí. Un sink con tenant_id nunca se empareja así: el tenant viaja en un secreto que Grafana nunca devuelve, así que nada puede saber si el datasource de esa dirección lee el mismo tenant, y se crea uno.

El panel de la salida del trabajo fallido sigue siendo una nota. Ese panel pasa a ser las líneas cuando hay un sink de Loki cuya dirección termina en /loki/api/v1/push, que es lo que dice dónde está el extremo de consulta. Un sink que escriba en otro sitio lo dice y deja el panel como está; nombra un datasource de Loki en grafana.datasource.loki_uid. Un token que no puede crear el datasource también lo deja así, con el aviso de arriba.

No se publicó nada y no falló nada. publish_on_start está apagado salvo que lo enciendas, y se salta en -once, -backfill y -card, porque encenderlo en una unidad de systemd no quería decir reescribir el dashboard en cada ejecución de una tarjeta programada.

El colector arrancó y el dashboard no apareció. Una publicación que falla al arrancar avisa y la pasada sigue. Las métricas de una hora sin recoger no se recuperan y un dashboard publicado al siguiente arranque sí, así que el sitio donde mirar es la línea del log.

-uninstall imprimió una lista y no quitó nada. Eso es lo que hace por omisión. Añade -yes.

El datasource sobrevivió al uninstall. Uno nombrado en grafana.datasource.uid se adopta, no se crea, así que era de otro antes de que esto corriera y sigue siéndolo.

unknown -uninstall target. Se rechaza la lista entera en vez de la parte que se entendió, así que una errata no quita nada. Los objetivos son dashboard, data, state y all.

Las filas siguen en la base después de -uninstall data. Tres almacenes no se pueden vaciar desde aquí y lo dicen: Graphite no tiene borrado, el sink de Prometheus se raspaba en vez de recibir escrituras, y el fichero del sink SQL se va pero las filas que ya cargaste de ahí a una base de verdad las cargaste tú.

Tablas o índices llamados gh_...-20261001T091004. Una migración apartó las filas antiguas de la medida con ese nombre, la medida, un guion y el instante en UTC: la tabla renombrada de PostgreSQL, el clon de Elasticsearch, allí en minúsculas, y el nombre que InfluxDB 3 da a una tabla que borró. Ninguno de los paneles que se distribuyen lee ninguna. ghchronicle purga las de PostgreSQL y Elasticsearch cuando llevan 24 horas guardadas, e InfluxDB 3 purga las suyas con su propio calendario, 72 horas después del borrado por omisión, salvo una que borró una versión anterior a la 3.2, que no se purga nunca, ni siquiera después de actualizar (ver antes de la 3.2 la copia se queda); -migrate las lista bajo su almacén como kept aside. -uninstall data quita las de PostgreSQL y Elasticsearch con todo lo demás, y deja fuera las de InfluxDB 3 con una nota que dice cuáles se quedan, porque el servidor rechaza el borrado de una tabla que ya ha borrado, o, antes de la 3.2, la renombra otra vez.

migration pending, en cada arranque. Un almacén guarda filas de una medida con una forma que esta versión ya no escribe, y este arranque no lo puso al día. not_applied dice por qué: migrate: warn, o un motivo por el que el cambio necesita la palabra de alguien, como un InfluxDB 2, cuya única vía es un borrado definitivo, un fichero SQL, un Graphite o un Telegraf, donde ghchronicle no aparta nada, filas de cuentas que esta configuración no recoge, filas que volver a leer no traería de vuelta, o filas cuyas cuentas o repositorios no se pudieron leer, lo que un InfluxDB 3 Core que pasa de su límite de ficheros por consulta se niega a decir; o una ejecución de una sola vez sobre un fichero de estado nuevo, cada ejecución de la Action sin uno restaurado, que no aplica nada por su cuenta. plan y apply son las dos órdenes, y first, en el servicio, dice que lo pares antes de la segunda. Se dice en cada arranque hasta que el almacén se pone al día: mira Migraciones.

applying a migration before the first sweep. No es un error. Con migrate: auto el arranque encontró un cambio que puede aplicar sin perder nada, y lo está aplicando: found es lo que guarda el almacén, action adónde van las filas antiguas, y refill lo que se vuelve a leer de GitHub. Sale una vez por almacén y cambio, seguido de refill starting, refill complete y reconciled, y luego la primera pasada.

migration noted: nothing is changed o migration frozen. Tampoco son errores. Una nota es un cambio que nada puede arreglar, como las filas de gh_actions_cache_entry fechadas antes de la 2.6.0, y una medida congelada es una que ya no escribe nada de lo que corre esta configuración. Cada una se dice una vez en INFO y después en DEBUG.

migration check failed: the store did not answer. Al arrancar se preguntó al almacén si guarda una forma antigua, y lo rechazó o no respondió en 30 segundos. No se anotó nada ni cambió nada; la pasada sigue, y el siguiente arranque vuelve a preguntar.

migration failed. El almacén rechazó lo que aplicar le pidió, y el cambio sigue pendiente; los demás almacenes siguieron adelante. err dice por qué, y el motivo habitual es una credencial que puede escribir y no borrar: el token de InfluxDB 3 tiene que poder borrar una tabla, y el error lleva el mismo borrado como un curl para ejecutarlo a mano; el usuario de PostgreSQL tiene que ser dueño de la tabla, como lo es cuando la creó su propio destino; una clave de Elasticsearch necesita manage y delete_index sobre los índices de su prefijo. PostgreSQL además se rinde tras tres esperas de 5 segundos cada una detrás de una consulta que tiene la tabla, y una consulta larga de Grafana puede serlo. Ejecuta la misma orden otra vez cuando esté arreglada la causa: lo aplicado queda anotado y no se hace dos veces.

refill did not finish, and is still owed. Volver a leer lo despejado se detuvo: se paró la ejecución, un almacén rechazó una escritura o GitHub no respondió. resume dice cómo seguir. El recorrido guarda su punto de control junto al fichero de estado, <nombre>-refill.json, y refill owed, en cosas que sí son errores, es lo que dice de él un arranque posterior.

the store may have been cleared, so the refill stays owed. Despejar el almacén falló de una manera que no dice si se llevó a cabo: un 502 de un proxy, un tiempo agotado, una conexión que se rompió después de que el almacén hiciera lo que se le pidió. La relectura se anotó como debida antes de tocar el almacén y sigue debiéndose, así que el historial se vuelve a leer ocurriera o no el despeje; el cambio se vuelve a preguntar en el siguiente arranque. Como mucho eso lee el historial una vez para nada.

the state file records a refill owed to ... where it no longer points. Una migración despejó un almacén, la relectura no terminó, y el destino apunta ahora a otro almacén. El registro se conserva, y la relectura se lee la próxima vez que el destino apunte allí; hasta entonces nada la lee. -migrate la muestra bajo el almacén como owed there.

not reconciled: the copy and the table could not be compared. El historial se volvió a leer, y la copia de las filas antiguas no se pudo leer, o ya tocaba purgarla. Lo que volvió está en la tabla; solo falta la lista de lo que GitHub ya no sirve, y mientras la copia siga ahí se puede leer a mano.

set-aside copy not purged o set-aside copies not listed. Un día después de que una migración la apartara, ghchronicle no pudo quitar la copia de PostgreSQL ni borrar el clon de Elasticsearch, o no pudo preguntar al almacén qué copias guarda. Lo vuelve a intentar tras cada pasada y en cada arranque; aside nombra la copia, que también se puede quitar a mano. InfluxDB 3 purga las suyas con su propio calendario, o, antes de la 3.2, nunca.

the cache file still claims what the cleared store held. Una migración no pudo reescribir el fichero de caché para olvidar los rechazos, y las ejecuciones de workflow ya escritas, de las familias que vuelve a leer, así que esas familias pueden seguir saltándose lo que el almacén despejado ya no guarda. Con el servicio parado, borrar <nombre>-cache.bin cuesta una pasada a precio completo: la caché que hay a su lado.

-migrate -yes responde process N (ghchronicle ..., service, since ...) holds ...-lock. El servicio, u otro -migrate -yes, tiene el fichero de estado, y no se cambió nada. Páralo, o deja que termine, y ejecuta la orden otra vez. En Docker, N es el proceso con el número que le da el contenedor del propio servicio.

waiting for the process holding the state file to finish. El servicio se arrancó mientras -migrate -yes corría sobre el mismo fichero de estado. Espera a que termine y luego arranca sobre lo que dejó.

another ghchronicle service keeps the same state file. Se arrancó un segundo servicio sobre un fichero de estado que ya tiene uno en marcha, y se rechazó, porque dos servicios que guardan un mismo fichero de estado deshacen las marcas del otro. Para uno, o da a cada uno su propio state_file.

the state file cannot be locked, so -migrate -yes cannot tell this service is running. El servicio no pudo crear ni abrir <nombre>-lock junto al fichero de estado: el directorio no es escribible, o una ejecución como otro usuario, casi siempre root, creó el fichero. El servicio corre sin el candado, y entonces -migrate -yes se niega a correr, porque nada impediría que el servicio arrancara por debajo de él a medias. Ejecútalo con el usuario del servicio: tras una actualización.

could not reach its database. El sink conecta en la primera escritura y no al arrancar, así que esto es la primera pasada y no la lectura de la configuración. El DSN admite las dos formas que admite libpq, y el mensaje es el del driver.

Falta una columna en vez de la fila. Un campo sin valor no ocupa celda: una cadena vacía se deja fuera, y un float que no es un número se guarda como NULL. La columna aparece la primera vez que un punto lleva algo para ella.

Un campo cambió de tipo y el insert falla. Una columna se crea con el tipo del primer valor visto y no se altera después, así que un campo que era un número y ahora es una cadena no tiene dónde ir. Renombra el campo, o tira la tabla, y la siguiente escritura del colector la declara otra vez. No hace falta reiniciar: el destino declara una tabla una vez por proceso, y el primer insert tras el borrado se rechaza porque la tabla no está, así que el destino olvida las tablas de ese lote, las declara de nuevo y reenvía el lote una vez.

Se rechazan las sentencias de gh_discussion_comment del fichero SQL. Con there is no unique or exclusion constraint matching the ON CONFLICT specification, reproducido en una tabla que creó una versión anterior a la 2.6.1. Esa tabla conserva is_answer en su clave, que la 2.6.1 ya no escribe, y el fichero no puede leer la clave de una tabla como hace el destino que conecta, así que sus upserts nombran una clave que la tabla no tiene. El resto del fichero se carga. -migrate -yes escribe en el fichero el borrado de esa tabla, antes de las filas que vuelve a leer, así que el fichero reproducido en orden carga entero: ver qué hace aplicarlo en cada almacén. A mano, tira la tabla, como describe la página de medidas, y vuelve a llenarla con un relleno histórico.

El sink de fichero y este no coinciden. Salvo por la clave de arriba, no pueden: los dos renderizan el mismo esquema desde el mismo código, y cmd/check_postgres planifica contra él cada consulta de panel. Si las tablas difieren, una se cargó desde una versión anterior.